4

これには多くの質問と回答がありますが、参照によって戻る必要がある理由が本当にわかりません。

ある場合 (オブジェクト MyObject に対して演算子が既に正しくオーバーロードされていると仮定します):

    MyObject obj1;
    MyObject obj2;
    cout << obj1 << obj2;

ここで、((cout << obj1) << obj2)); のような部分式があります。問題は、なぜ値で返せないのかということです。(わかりました、値として ostream を返すことが許可されていると仮定しましょう) cout << obj1 が参照ではなくストリーム オブジェクトを返す場合、違いは何ですか? なぜ連鎖が不可能なのですか?「=」演算子のオーバーロードと同様に、値で返す場合、A=B=C=D のようにチェーンすることはできません。なんで ?


回答ありがとうございます。参照渡しなしで連鎖できることはわかっていますが、「=」をオーバーロードすると、出力がまったく異なります。私が書く場合:

    class Blah{
    public:
       Blah();
       Blah(int x, int y);
       int x;
       int y;
       Blah operator =(Blah rhs);
     };
     Blah::Blah(){}
     Blah::Blah(int xp, int yp){
       x = xp;
       y = yp;
     }
     Blah Blah::operator =(Blah rhs){
       Blah ret;
       ret.x = rhs.x;
       ret.y = rhs.y;
       return ret;
     }
    int main(){

      Blah b1(2,3);
      Blah b2(4,1);
      Blah b3(8,9);
      Blah b4(7,5);
      b3 = b4 = b2 = b1;
      cout << b3.x << ", " << b3.y << endl;
      cout << b4.x << ", " << b4.y << endl;
      cout << b2.x << ", " << b2.y << endl;
      cout << b1.x << ", " << b1.y << endl;
          return 0;
     }

これからの出力は次のとおりです。8,9 7,5 4,1 2,3

しかし、参照渡しでオーバーロードし、パラメーターを参照として設定し、代わりにオーバーロードするときに *this を変更して返すと、次のようになります: 2,3 2,3 2,3 2,3

最初の例でオブジェクトが変更されない理由は何ですか? 左辺値と右辺値が原因ですか? 比較すると、省略形の演算子はどうですか?


わかりました、別の更新。前述のとおり、正しい結果はすべて 2,3 である必要があります。ただし、オーバーロードされた演算子を次のように書くと:

     Blah Blah::operator =(Blah rhs){
       x = rhs.x;
       y = rhs.y;
       return *this;
     }

その後、正しい結果が得られます。(2,3 2,3 2,3 2,3)。*this はどうなりますか? オーバーロードされた演算子は、オーバーロード関数で lhs を rhs で更新しますが、*this を返すことは無意味に思えます。*これはどこで終わるのですか : b3 = b4 = b2 = b1 ? チェーンが b3 に達したときに実際には何も返さないように、左に戻ろうとしますか (それは左に戻ろうとします)?

4

5 に答える 5

8

主な理由は、値を返すとコピーが作成され、iostream オブジェクトはコピーできないためです。それらには状態と ID があり、それらをコピーすることが何を意味するのかは明確ではありません。オブジェクトには (論理的には少なくとも) ストリーム内の位置が含まれているため、コピーを作成すると、2 つのオブジェクトが同じ位置に書き込まれます。ストリーム。

于 2013-02-18T11:52:31.040 に答える
2

値で返すことは連鎖を妨げません。しかし、値で返す場合は、copyを返すことになります。これは、通常、この場合に必要なものではありません。

于 2013-02-18T11:45:07.650 に答える
1
Blah Blah::operator =(Blah rhs){
Blah ret;
ret.x = rhs.x;
ret.y = rhs.y;
return ret;
}-->(1)

Blah b1(2,3);
Blah b2(4,1);
Blah b3(8,9);
Blah b4(7,5);

b3 = b4 = b2 = b1;---->(2)

(2) を呼び出すと、=() が呼び出されます。上記のスニペット (1) では、一時オブジェクトを返しています。実際のオブジェクトの x 値を更新していないことに注意してください。たとえば、操作は次のように開始します b2(x ,y) = b1(2,3) であり、一時オブジェクト ret で値 2 & 3 を初期化し、一時オブジェクトを値で返します。そのため、一時オブジェクトは b4 を呼び出します。つまり、b4 = temp(2,3 ) そして再び同じ Funda.you は 2 と 3 を b4 にコピーし、b3 を呼び出している一時オブジェクトを b3 = temp(2,3) として返します。(2) をこの印刷された cout << b3=b4 のように置き換えると=b2=b1 (<< オーバーロードを実装する場合)、2 & 3 はこの行でのみ使用できるため、出力として 2 & 3 が得られます。あなたの例では、呼び出したオブジェクトの x & y の値を更新していないという理由だけで、この値が利用できない次の行に印刷しています。そのためには、参照として *this を返す必要があります。 b2=b1 を実行して *this を返すと、関数 .SO を呼び出したオブジェクトが返されます。つまり、実際のオブジェクトが返され、実際のオブジェクトの x、y 値が更新され、オブジェクトが存在します。

于 2013-08-22T13:31:19.023 に答える
1
Blah Blah::operator =(Blah rhs){
   Blah ret;
   ret.x = rhs.x;
   ret.y = rhs.y;
   return ret;
 }
  Blah b1(2,3);
  Blah b2(4,1);
  Blah b3(8,9);
  Blah b4(7,5);
  b3 = b4 = b2 = b1;

b3はその rhs として取り込もうとしてb4いますが、実際には の値を変更しているのではなくb3、同じ型の新しい変数を作成しBlahて null に戻しています (この場合、 null は の左側に何もないため、何も意味しませんb3。の左側に何かがあったb3としても、別の変数が および と同じことを行うため、違いはありませBlahん。b3b4

実際、別のクラス (x と y も持つ CoolClass など) があり、代入演算子をオーバーロードして何とか変数を取り込み、実際に独自の x と y を変更する場合、それが見つかります。

coolObject = b3 = b4 = b2 = b1; //CoolObject.x = 2, CoolObject.y = 3

参照渡しに関するあなたの主な不満が何であるかはまだ正確にはわかりません。Blah の演算子を次のように記述します。

Blah & Blah::operator = (const Blah & rhs) { x = rhs.x; y = rhs.y; return *this; }

これにより、rhs が可変でなく、連鎖動作が適切に機能することが保証されます。

別の種類のオブジェクト (たとえば ostream など) でより良い動作を探している場合は、フレンド関数を宣言すると役立つ場合があります。これらは、新しいクラスで宣言できる関数ですが、クラスに直接属していません。このアプローチの利点は、ostream クラスに由来するように見えるオペレーターを持つことですが、代わりに Blah クラスにあります。フレンド関数内でプライベートおよび保護されたメンバーを引き続き使用できるため、便利です。

friend std::ostream & Blah::operator << (std::ostream & lhs, const Blah & rhs)
{ return lhs << "{" << rhs.x << ", " << rhs.y << "}"; }

これにより、同じ ostream オブジェクトが渡され、優先順位に従ってデータが埋められます。通常のテキストと ostream で見られると予想される動作とまったく同じです。

最初の例を使用すると、このように考えることができます。と の両方がであると仮定するobj1と、オブジェクトはフレンド関数を介して受け取り、 のデータによって変更された同じオブジェクトを返します。次に、新しく変更されたオブジェクトが受け取り、再び同じ変更されたオブジェクトを返しますが、によっても変更されます。obj2Blahcoutobj1coutobj1coutobj2coutobj2

(cout << obj1) << obj2;
于 2013-02-18T14:46:40.330 に答える