作业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

posted @ 2020-03-12 14:10  timeaftertime  阅读(388)  评论(0编辑  收藏  举报