演算子のオーバーロード、コピー深さ

いくつかの算術シンボルの(+、 - 、*、/ ....)、我々は、操作の元のモードに満足していないが、となるように一意のオブジェクト(例えば、負の数の加算と減算されるように)使用して、しかしコンパイラましたオペレータがされますので、そうすることが許可されます、元の型の不一致操作が失敗しました。だから我々は我々のニーズを満たすために新しい意味を与える演算子をオーバーロードする必要があります。

complexa + comple_b:complex_aとcomplex_bように、2つの複雑なオブジェクトはに直接書き込むことを期待して、二つは複雑で、需要があります

の演算子オーバーロードのオブジェクトは、次のとおり、オブジェクトに作用することができるように、オペレータは、C ++で提供されるアプリケーションを拡張します

同じ演算子、オペランドの異なる種類の異なる挙動は、発生しました。
複数の対象について:complex_a + complex_b =>は、新たな複数の参照生成
5 + 4 = 9:整数をを

オーバーロードオペレータエッセンス関数のオーバーロード通常のオーバーロードとして機能することができる、部材をオーバーロードすることができる変換アルゴリズムを含む式は、オーバーロードされた操作を完了するために、対応する演算子関数を呼び出している間、。マッチパラメータのタイプに応じて

1  クラスコンプレックス 
 2  {
 3      公共ダブル実、IMAG。 
4      複合体(二重 R = 0.0ダブル I = 0.0 ):実際の(R)、IMAG(I){}
 5      コンプレックス演算子 - (CONSTコンプレックス&C)。 
6  }。
7複合演算子 +(CONST&コンプレックス、CONSTコンプレックス&B)
 8  {   
 9      戻りコンプレックス(a.real + b.real、a.imag + b.imag)。//一時オブジェクトを返し
10  }
 。11コンプレックスコンプレックス:: 演算子 - (CONSTコンプレックス&C)
 12である {
 13で     返す(レアル- c.real、IMAG - c.imag)錯体; // 一時的なオブジェクトを返す
14  }
 15  // 重量キャリアはメンバ関数である場合、パラメータの数は、オペレータの数を減少させます。
16  // 重負荷機能は、オペレータの数のようなパラメータの数正常です。
17  INT メイン()
 18は 、{
 。19      コンプレックスA(44)、B(11 )、C;
 20である      ; C = A + B // 演算子+ = C(A、B)に相当する
21れます     coutの<< c.real << " " << c.imag <<てendl; // 5,5、22      COUT <<(AB).real << " " <<(AB).imag << ENDL。// 3,3
 23 // AB等价于a.operator-(B)24 リターン0 25 }
     
      
  • 代入演算子のオーバーロード

時々代入演算子の所望のタイプの両側がオペレータと一致しない場合があり、例えば、int型の変数に複雑なオブジェクト、割り当ての文字列型にchar *文字列の割当てをオブジェクト、その後、代入演算子をオーバーライドする必要が記号"="。代入演算子は「=」のみメンバ関数としてオーバーロードすることができます

 1 class String 
 2 {
 3     private:    
 4         char * str;
 5     public:
 6         String ():str(new char[1]) { str[0] = 0;}
 7         const char * c_str() { return str; };
 8         String & operator = (const char * s);
 9     String::~String( ) { delete [] str; }
10 };
11 String & String::operator = (const char * s) 
12 { //重载“=”以使得 obj = “hello”能够成立
13     delete [] str;
14     str = new char[strlen(s)+1];
15     strcpy( str, s);
16     return * this;
17 }
18 int main()
19 {
20     String s;
21     s = "Good Luck," ; //等价于 s.operator=("Good Luck,");
22     cout << s.c_str() << endl;
23     // String s2 = "hello!"; //error
24     s = "Shenzhou 8!"; //等价于 s.operator=("Shenzhou 8!");
25     cout << s.c_str() << endl;
26 return 0;
27 }
28 // 输出:
29 // Good Luck,
30 // Shenzhou 8!
  • 浅拷贝和深拷贝

一个字符串的例子

1 String S1, S2;
2 S1 = “this”;
3 S2 = “that”;
4 S1 = S2;

这几句的含义很清楚,一个S1串和S2串,并将S2赋值给S1,此时S1就和S2是一样的值。。但是....这样却不是我们理解的那种copy

它是在将s2赋值给s1的时候,将原来指向s1的指针取指向s2

原本指向'this'字符串的指针s1指向了'that'的字符空间,这样原来的'this'的字符空间就找不到了(变成内存垃圾)。

这就是浅拷贝此时若我们释放s1所指向的存储空间,将会释放掉'that',但是继续释放s2时,会发生问题(程序崩溃),因为此刻s2指向的存储空间已经被s1所释放了

但是原来的'this'却孤独的无人问津,好惨 ...所以这样是很不妥的。。。或者,我们更换此刻s1的值,又导致'that'被更换了。。。就会一团糟。。

所以需要对原来的'='号进行重载(深拷贝:生成一个新的,值与当前的值一样的,不同地址空间的复制,互相的操作不相往来的那种,即真正意义上的copy)

 1 class String 
 2 {
 3 private: 
 4     char * str;
 5 public:
 6     String ():str(new char[1]) 
 7     { 
 8         str[0] = 0;
 9     }
10     const char * c_str() 
11     { 
12         return str; 
13     };
14     String & operator = (const char * s)
15     {
16         delete [] str;//删除原来的str
17         str = new char[strlen(s)+1];//开辟足够大的存储空间
18         strcpy( str, s);//将s拷贝过来
19         return * this;//这样s1就会指向新分配的存储空间
20     };
21     ~String( ) 
22     { 
23         delete [] str; 
24     }
25 };

但是,这样写还是有一点小问题的。如果我写了这个 s=s,就问又有小问题。这样在赋值时,左边的s先被delete,然后将右边s赋值给左边的s,但是右边的s已经没了啊?!?!?这样就出错了。所以代码要继续修改,成这样

1 String & operator = (const String & s)
2 {
3     if( this == & s) //
4         return * this;//防止出现自己给自己赋值出错的情况,直接返回就行了
5     delete [] str;
6     str = new char[strlen(s.str)+1];
7     strcpy( str,s.str);
8     return * this;
9 }

注意,返回值类型是String & 型这样是为了对应原来 “=”运算符的左右两边类型

1 //
2 a = b = c;
3 (a=b)=c; //会修改a的值
4 //分别等价于:
5 a.operator=  (b.operator=(c));
6 (a.operator=(b)).operator=(c);

现在应该可以了。

但是。。。。

1 //为 String类编写复制构造函数的时候,会面临和不重载的 = 同样的问题,即默认构造函数会将=变成复制的操作,是浅拷贝!!所以我们用同样的方法处理。写个复制构造
2 String( String & s) 
3 {
4     str = new char[strlen(s.str)+1];
5     strcpy(str,s.str)
6 }

 

おすすめ

転載: www.cnblogs.com/ygsworld/p/11324550.html