选用网课:中国大学MOOC平台,北大的程序设计与算法(三)C++面向对象程序设计
教师:郭炜
时间:2019.8.11
目标:加深对于C++中面向对象的理解
1.基本概念理解加深
-运算符重载的实质是函数的重载(;不只是狭义上的+ - * /等)
-优先重载为成员函数,在需要全局调用时,考虑友元函数
-把含运算符的表达式转换为对成员函数的调用来理解(a-b等价于a.operator+等)操作数转换为函数参数
2.赋值运算符的重载
使得赋值运算符两边类型可以不匹配,=只能重载为成员函数。为了保持一致性,=的返回值为左值的引用
如果左值正是该类,即可return *this;
注意浅复制和深复制的区别尤其是有Pointer时
eg.S1=S2,此时s1指针也指向了同一片区域,然而s1原来所指向区域成为了内存垃圾。
3.运算符重载为友元函数
我们希望,比如+,不仅可以c+5,也可以5+c
4.可变长数组的一个实例
这里注意 []
的重载返回值,根据具体需求,有时是int&有时是int*
-还有一个是,要注意区分复制构造函数的浅复制坑,默认的复制构造函数只会完成成员的复制,当成员是指针时便容易发生问题
//这里的一个常规操作是,先划区域,再strcpy
//同时注意防止s=s问题
if(ptr==a.ptr)
return *this;
else
ptr=new int[strlen(a.ptr)+1];
strcpy(ptr,a.ptr);
5.流插入和流输入运算符
cout是在iostream中定义的,ostream类的对象
<<
本身是左移运算符,在iostream中得到了重载
对于我们的需求,需要将<<重载为全局函数,又可以访问类的私有成员,友元函数最佳。返回值仍需要为ostream对象,以满足连续输出。
eg.
friend ostream & operator<<(ostream &o, A &a){
o<<a.num;
return o;}
注意这里的ostream &o
中,去掉&会报错,老师也没细讲原因。
6.类型转换运算符的重载
operator double(){...}
肯定无参数,无返回值类型
(int)s
等价于s.int()
在一些自定义类隐式转换中可以很好地解决问题。
7.自增自减运算符重载
为了区分++i与i++,C++规定后置运算符,需要多一个无用的int变量,以示区分。
-还有要注意的是,返回值不同。前置返回自增完的对象,后置返回自增前的备份(temp)
T & operator++()//++i
{n++;return *this;}
T operator++(int)//i++
{T tmp(*this);//备份
n++;
return tmp;}
几点注意
重载不改变优先级
.
,.*
,::
,?:
,sizeof
不能被重载
()、[]、->、=只能重载为成员函数
程序填空练习题
1.MyString
这题比较常规,关于赋值号的重载,还有个流输出重载,因为不涉及连续赋值(形如a=b=c),返回值可以设为void
但为了养成习惯,保持优雅,最好返回值设为MyString &
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
class MyString {
char * p;
public:
MyString(const char * s) {
if( s) {
p = new char[strlen(s) + 1];
strcpy(p,s);
}
else
p = NULL;
}
~MyString() { if(p) delete [] p; }
//begin of my code
MyString(MyString &s){
p=new char[strlen(s.p)+1];strcpy(p,s.p);
}
void operator=(const char * s) {
if(s) {
p = new char[strlen(s) + 1];
strcpy(p,s);
}
else
p = NULL;
}
void operator=(const MyString &s) {
if(s.p) {
p = new char[strlen(s.p) + 1];
strcpy(p,s.p);
}
else
p = NULL;
}
friend ostream &operator<<(ostream &o,const MyString &s){
o<<s.p;
return o;
}
void Copy(const char * w){
p=new char[strlen(w)+1];strcpy(p,w);
}
//End of my code
};
int main()
{
char w1[200],w2[100];
while( cin >> w1 >> w2) {
MyString s1(w1),s2 = s1;
MyString s3(NULL);
s3.Copy(w1);
cout << s1 << "," << s2 << "," << s3 << endl;
s2 = w2;
s3 = s2;
s1 = s3;
cout << s1 << "," << s2 << "," << s3 << endl;
}
}
2.看上去好坑的运算符重载
这道题初次分析卡了会儿,以为是输出的n-5,n-7后来明白了Inc只是在输出时+1并没有改变,是输出n-5,n-8。
另一个点,注意到Inc()的参数是Int,而主函数中的调用时Myint型
我的初次解决方案是,在类中写了个Inc的重载函数
后来发现,可以直接写一个类型转换重载函数,重载int(),使主函数调用Inc是,隐式调用(int)可以通过。
#include <iostream>
using namespace std;
class MyInt
{
int nVal;
public:
MyInt( int n) { nVal = n ;}
//Begin of my code
MyInt & operator-(const int &a){
nVal-=a;return *this;
}
friend int Inc(MyInt &a){
return a.nVal+1;
}
};
int Inc(int n) {
return n + 1;
//End of my code
}
int main () {
int n;
while(cin >>n) {
MyInt objInt(n);
objInt-2-1-3;
cout << Inc(objInt);
cout <<",";
objInt-2-1;
cout << Inc(objInt) << endl;
}
return 0;
}
上面的友元函数可以代替为
operator int()
{
return nVal;
}
4.二维数组类
这题卡了会儿,一开始的方案就是动态分配二维数组,但之前没有在类内存储行和列,一直卡在怎样通过动态分配的二维数组来获得行和列数。后来屈服了,在类内存储了行和列,一切自然解决了。
这里还考察了括号的重载,[]的重载。
网上关于数组存储,也可以使用静态分配的方法。那么可以用sizeof来判断行和列。
#include <iostream>
#include <cstring>
using namespace std;
class Array2 {
//Begin of my code
int **num;
int col;int row;
public:
Array2(int a,int b):row(a),col(b){
num=new int*[a];
for(int i=0;i<a;++i){
num[i]=new int[b];
}
}
Array2(){num=NULL;
}
Array2 &operator=(Array2 &p){
int l1=p.row;//行数
int l2=p.col;
num=new int*[l1];
for(int i=0;i<3;++i){
num[i]=new int[l2];
for(int j=0;j<4;++j){
num[i][j]=p.num[i][j];
}
}
return *this;
}
int* operator[](int &n){
return num[n];
}
int operator()(int& a,int& b){
return num[a][b];
}
//End of my code
};
int main() {
Array2 a(3,4);
int i,j;
for( i = 0;i < 3; ++i )
for( j = 0; j < 4; j ++ )
a[i][j] = i * 4 + j;
for( i = 0;i < 3; ++i ) {
for( j = 0; j < 4; j ++ ) {
cout << a(i,j) << ",";
}
cout << endl;
}
cout << "next" << endl;
Array2 b; b = a;
for( i = 0;i < 3; ++i ) {
for( j = 0; j < 4; j ++ ) {
cout << b[i][j] << ",";
}
cout << endl;
}
return 0;
}
5.别叫,这个大整数已经很简化了!
这道题乍看确实感觉挺麻烦的,需要自己做大数加法重载,判断进位等等。
参考了篇资料,将大数反向按字节存储,整型同样处理可以解决问题。
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
using namespace std;
const int MAX = 110;
class CHugeInt {
private:
char maxNum[210];
int len;
public:
CHugeInt(char * s){
strcpy(maxNum,s);
int i=0,j=strlen(s)-1;
while(i<j)
{
swap(maxNum[i],maxNum[j]);
i++;
j--;
}
//cout<<"init:"<<maxNum<<endl;
len=strlen(s);
//cout<<"Init success"<<endl;
}
CHugeInt(){
len=0;
}
CHugeInt(int n){
int i=0;
if(n==0)
{
maxNum[i++]='0';
}else{
while(n)
{
maxNum[i++]=n%10+'0';
n=n/10;
}
}
maxNum[i]='\0';
len=i;
//cout<<maxNum<<endl;
}
CHugeInt operator+(CHugeInt & a)
{
//cout<<"hrer"<<endl;
int i=0,j=0;
int t,sum=0;
CHugeInt temps;
strcpy(temps.maxNum,maxNum);
temps.len=len;
//cout<<"before:"<<temps.maxNum<<endl;
//maxNum=new char[strlen(a.maxNum)+1];
//cout<<a.len<<","<<len<<endl;
int flag=0;
while(j<a.len&&i<temps.len)
{
t=a.maxNum[j]-'0';
int te=temps.maxNum[i]-'0';
sum=t+te;
//cout<<t<<"+"<<te<<":"<<sum<<endl;
if(sum>=10)
{
temps.maxNum[i]=sum%10+'0';
//cout<<temps.maxNum[i]<<endl;
temps.maxNum[i+1]=sum/10+temps.maxNum[i+1];
if(i+1>=temps.len)
{
temps.maxNum[i+1]+='0';
}
flag=1;
}else{
//cout<<"sum:"<<sum<<endl;
flag=0;
temps.maxNum[i]=sum+'0';
}
//cout<<temps.maxNum[i]<<endl;
i++,j++;
sum=0;
}
while(j<a.len)
{
if(flag==1)
{
temps.maxNum[i+1]=a.maxNum[j];
i++,j++;
}else{
temps.maxNum[i]=a.maxNum[j];
i++,j++;
}
}
if(i>=len)
{
if(flag==1){
temps.maxNum[i+1]='\0';
temps.len=i+1;
}
else{
temps.maxNum[i]='\0';
temps.len=i;
}
}
return temps;
}
/*operator char *()
{
return maxNum;
}*/
CHugeInt & operator +=(int n)
{
CHugeInt temps(n);
*this=this->operator+(temps);
//cout<<this->maxNum<<endl;
return *this;
}
friend ostream & operator<<(ostream & os,const CHugeInt & s)
{
int i=0,j=s.len-1;
//cout<<"len:"<<s.len<<endl;
//cout<<"输出:"<<s.maxNum<<endl;
for(;j>=i;j--)
os<<s.maxNum[j];
return os;
}
friend CHugeInt operator+(int n,CHugeInt s)
{
CHugeInt temps(n);
s=s+temps;
return s;
}
friend CHugeInt operator+(CHugeInt s,int n)
{
CHugeInt temps(n);
s=s+temps;
return s;
}
CHugeInt & operator++()
{
(*this)+=1;
//cout<<"前置自增后:"<<this->maxNum<<endl;
return *(this);
}
CHugeInt operator++(int n)
{
CHugeInt temps;
strcpy(temps.maxNum,maxNum);
temps.len=len;
this->operator +=(1);
//cout<<temps.maxNum<<endl;
//cout<<"len:"<<temps.len<<endl;
return temps;
}
};
int main()
{
char s[210];
int n;
while (cin >> s >> n) {
CHugeInt a(s);
CHugeInt b(n);
cout << a + b << endl;
cout << n + a << endl;
cout << a + n << endl;
b += n;
cout << ++ b << endl;
cout << b++ << endl;
cout << b << endl;
}
return 0;
}
网友评论