作业4-运算符重载
1.MyString
补足MyString类,使程序输出指定结果
1 //补足MyString类,使程序输出指定结果 2 #include <iostream> 3 #include <string> 4 #include <cstring> 5 using namespace std; 6 class MyString { 7 char * p; 8 public: 9 MyString(const char * s) { 10 if( s) { 11 p = new char[strlen(s) + 1]; 12 strcpy(p,s); 13 } 14 else 15 p = NULL; 16 17 } 18 ~MyString() { if(p) delete [] p; } 19 // 在此处补充你的代码 20 MyString(const MyString & s){ //初始化的时候p肯定就是NULL 21 if(s.p==NULL) p = NULL; 22 else{ 23 p = new char[strlen(s.p) + 1]; 24 strcpy(p,s.p); 25 } 26 } 27 void Copy(const char * s){ 28 if(p) delete [] p; //一定要先删掉!! 29 if(s){ 30 p = new char[strlen(s) + 1]; 31 strcpy(p,s); 32 } 33 else p = NULL; 34 } 35 MyString & operator = (const char * s){//返回值要是引用,是为了处理连等情况 36 if(p) delete [] p; 37 if(s){ 38 p = new char[strlen(s)+1]; 39 strcpy(p ,s); 40 return *this; 41 } 42 43 } 44 MyString & operator = (const MyString & s){ //需要是深拷贝 45 if(p) delete [] p; 46 p = new char[strlen(s.p)+1]; //为什么非要new? 47 strcpy(p, s.p); 48 return * this; 49 } 50 friend ostream & operator<<(ostream & o, const MyString & s){ //必须得是友元才能访问私有对象,友元函数可以写在类里面 51 o << s.p ; //但是p是私有成员,所以要搞成友元 52 return o; //返回cout的引用 53 } 54 }; 55 56 int main() 57 { 58 char w1[200],w2[100]; 59 while( cin >> w1 >> w2) { 60 MyString s1(w1),s2 = s1; //需要自己写一个复制函数 61 MyString s3(NULL); 62 s3.Copy(w1); 63 cout << s1 << "," << s2 << "," << s3 << endl; 64 65 s2 = w2; //需要重载=号 66 s3 = s2; 67 s1 = s3; 68 cout << s1 << "," << s2 << "," << s3 << endl; 69 70 } 71 }
备注:应该先观察main函数,发现有几个要点:
1.要自己写一个复制构造函数,确保s2=s1是深拷贝(我最后就是这一步忘记了导致RE,因为浅拷贝会在s2=w2时使s1指向的MyString也修改,这样之后就会有问题)
2.写一个Copy函数(这个函数不需要有返回值),函数体和复制构造函数差不多,要注意的是,复制构造函数是在初始化时被调用,所以不需要delete原有的p,但copy时一定要删掉本来p指向的内存空间。然后就是注意深拷贝的写法,要先new出来一个空间,然后用strcpy把字符串粘过去
3.重载=号,参数为字符串指针,对应的是s2=w2那一行,和复制构造函数的写法也很像,但要注意返回值是*this,还要注意一下函数头是怎么写的
4.重载=号,参数为MyString类(的引用),对应66行s3=s2。
5.重载流插入运算符<<。这个函数是全局函数,但是因为是MyString类的友元,这道题又是个程序填空题,所以就把它写在类里面。
ps.我的这几个函数写的都不是很严谨,因为就只考虑了题目要求。按理说应该每个函数都先判断一下s是不是为空,再执行复制操作,否则是没有strlen(s)的;另外就是要考虑s=s这种情况,应该加一句if(this==&s) return *this。虽然这道题里没有涉及,我就没写。
2.看上去好坑的运算符重载
1 /*输入 2 多组数据,每组一行,整数n 3 输出 4 对每组数据,输出一行,包括两个整数, n-5和n - 8 5 */ 6 #include <iostream> 7 using namespace std; 8 class MyInt 9 { 10 int nVal; 11 public: 12 MyInt( int n) { nVal = n ;} 13 // 在此处补充你的代码 14 MyInt & operator-(const int n){ //这里比较特殊,需要-等同于-=。 15 nVal-=n; 16 return *this; 17 } 18 operator int(){ //重载类型转换运算符!! 19 return nVal; 20 } 21 }; 22 int Inc(int n) { 23 return n + 1; 24 } 25 int main () { 26 int n; 27 while(cin >>n) { 28 MyInt objInt(n); 29 objInt-2-1-3; 30 cout << Inc(objInt); //这里需要重载类型转换运算符 31 cout <<","; 32 objInt-2-1; 33 cout << Inc(objInt) << endl; 34 } 35 return 0; 36 }
备注:这道题需要重载减号和类型转换运算符。
其中减号的重载比较特殊,返回值需要是引用,因为-相当于-=。一般情况下返回值是对象就可以。
类型转换运算符的写法要注意!!
3.惊呆!point竟然能这样输入输出
1 /*输入 2 多组数据,每组两个整数 3 输出 4 对每组数据,输出一行,就是输入的两个整数 5 */ 6 #include <iostream> 7 using namespace std; 8 class Point { 9 private: 10 int x; 11 int y; 12 public: 13 Point() { }; 14 // 在此处补充你的代码 15 friend istream & operator>> (istream & is, Point & p){ //这里point不能是const啊!! 16 is>>p.x>>p.y; 17 return is; 18 } 19 friend ostream & operator<< (ostream & o,const Point & p){ 20 o<<p.x<<","<<p.y; 21 return o; 22 } 23 }; 24 int main() 25 { 26 Point p; 27 while(cin >> p) { 28 cout << p << endl; 29 } 30 return 0; 31 }
备注:这道题要注意的就是流提取的参数肯定不能是const啊……不然怎么输入,我太蠢了。其实记运算符重载怎么写的要点就在于函数名是operator和你要重载的那个运算符。然后流提取和流插入比较特殊,要记住返回值和参数都需要是引用。
4.[]的重载
/*写一个二维数组类 Array2,使得下面程序的输出结果是: 0,1,2,3, 4,5,6,7, 8,9,10,11, next 0,1,2,3, 4,5,6,7, 8,9,10,11, */ #include <iostream> #include <cstring> using namespace std; class Array2 { // 在此处补充你的代码 private: int x, y; int *p; //用一个一维数组来存 public: Array2(int xx, int yy):x(xx), y(yy){p = new int[xx*yy];} //构造函数里new了就要记得写析构函数!! Array2(){ x = 0; y = 0; p = NULL; } ~Array2(){ if(p) delete []p; } int * operator[](int i){ //[]的重载需要是一个指针,这样才能访问p[i][j] //注意[]其实有两个参数!!!只有第一个参数为Array2的时候才会调用,这就是为什么第二个中括号是正常访问数组下标! return (p+i*y); } int operator()(int i, int j){ return p[i*y+j]; } Array2 & operator=(const Array2 & a){ if(p) delete[]p; x = a.x; y = a.y; p = new int[x*y]; //注意一定是中括号!! memcpy(p, a.p, sizeof(int)*x*y); //注意memcpy的使用! return *this; } }; 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; }
备注:这道题一个是要注意别忘了写析构函数!!!二是比较神奇的一个地方,用一个一维数组存二维数组,然后重载中括号。为什么可以实现只重载第一个中括号呢?我问了助教才知道orz因为[]这个运算符实际有两个参数,一个是[]前面的a,一个是[]里面的i,只有在a是Array2这个新类型时,才会调用重载;那么第一个中括号已经调用了重载,返回值是一个指针,对于第二个中括号来说,两个参数就是 int* 和 int,就是正常的数组下标,就不会调用重载了!!
还有就是我最后犯了一个错误,p = new int[x*y]一定是中括号!!有一个无良程序写成了小括号,我查了一下发现小括号是指把这个整型初始化成了x*y,这显然不对!
5.别叫,这个大整数已经很简化了!
1 #include <iostream> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cstdio> 5 using namespace std; 6 const int MAX = 110; 7 class CHugeInt { 8 // 在此处补充你的代码 9 char s[200]; 10 public: 11 void reverse(char *a){ 12 int i = 0, j = strlen(a)-1; 13 while(i < j){ 14 swap(a[i], a[j]);//原来真有这个神奇函数? 15 i++; 16 j--; 17 } 18 } 19 CHugeInt(char *a){ 20 memset(s, 0, sizeof(s)); //先清零! 21 strcpy(s, a); 22 reverse(s); 23 } 24 CHugeInt(int a){ 25 memset(s, 0, sizeof(s)); //先清零! 26 int tmp = 0; 27 if(a == 0) s[0] = '0'; //一定要加上这行!!否则如果a是0,CHugeInt里就没有数了! 28 else{ 29 while(a > 0){ 30 s[tmp] = '0'+a%10; 31 tmp++; 32 a/=10; 33 } //还可以用一个函数sprintf(s,"%d",n); 34 } 35 } 36 CHugeInt operator+(const CHugeInt &a){ 37 CHugeInt ans(0); 38 if(a.s[0]=='0'&&strlen(a.s)==1) //特判0 39 return *this; 40 if(s[0]=='0'&&strlen(s)==1){ 41 strcpy(ans.s,a.s); 42 return ans; 43 } 44 int j = 0; //进位 45 int len = max(strlen(s), strlen(a.s)); 46 for(int i = 0; i < len; i++){ 47 int x = 0; 48 int a1 = max(s[i]-'0',0);//防止是s[i]==0的情况 49 int a2 = max(a.s[i]-'0',0); 50 x = a1+a2+j; 51 j = x/10; 52 x%=10; 53 ans.s[i] = '0'+x; 54 } 55 if(j!=0) 56 ans.s[len]=j+'0'; 57 return ans; 58 } 59 CHugeInt operator +(int n) { 60 return *this + CHugeInt(n); 61 } 62 CHugeInt operator +=(int n){ 63 *this = *this + n; 64 return *this; 65 } 66 friend CHugeInt operator +(int n, CHugeInt &num) { //转成了上一类。这需要是一个全局函数。运算符重载为友元函数 67 return num + n; 68 } 69 friend ostream& operator<<(ostream & o, const CHugeInt& num){ //ostream这个参数就正经地写成const别瞎写orz 70 for(int i = strlen(num.s)-1; i >= 0; i--) 71 o<<num.s[i]; 72 return o; 73 } 74 CHugeInt operator++(){//前置形式 75 *this = *this + 1; 76 return *this; 77 } 78 CHugeInt operator++(int){ //后置形式 79 CHugeInt record(*this); 80 *this = *this + 1; 81 return record; 82 } 83 }; 84 int main() 85 { 86 char s[210]; 87 int n; 88 89 while (cin >> s >> n) { 90 CHugeInt a(s); 91 CHugeInt b(n); 92 cout << a + b << endl; 93 cout << n + a << endl; 94 cout << a + n << endl; 95 b += n; 96 cout << ++ b << endl; 97 cout << b++ << endl; 98 cout << b << endl; 99 } 100 return 0; 101 }
备注:
这道题还是又硬核又有趣的。首先就是高精度运算大整数都要倒着写,然后要先写一个reverse函数,C++标准库里居然真的有swap这个函数!!太神奇了吧。构造函数里就先倒过来存起来,但一定要注意清零!!还有就是因为我是手动把整型转成字符串的,一定要注意0这种情况的特判!就像在运算时也要注意避免出现0-‘0’这种情况的出现。还有就是为了满足加法交换律+号要重载好几次,但都可以巧妙地转换成写好的第一类哈哈哈。还有就是自增运算符的重载注意一下,前置(成员函数)没有参数,后置有一个没用的参数orz