0

以下のコードを見て、それに関する私の質問に答えてください。

class Vector
{
public:
    int x, y;
    /* Constructor / destructor / Other methods */
    Vector operator + (Vector & OtherVector);
    Vector & operator += (Vector & OtherVector);
};

Vector Vector::operator + (Vector & OtherVector)  // LINE 6
{
    Vector TempVector;
    TempVector.x = x + OtherVector.x;
    TempVector.y = y + OtherVector.y;
    return TempVector;
}

Vector & Vector::operator += (Vector & OtherVector)
{
    x += OtherVector.x;
    y += OtherVector.y;
    return * this;
}

Vector VectorOne;
Vector VectorTwo;
Vector VectorThree;

/* Do something with vectors */
VectorOne = VectorTwo + VectorThree;
VectorThree += VectorOne;

このコードは本から抜粋したものですが、そこにはあまり説明がありません。具体的には、6行目以降のプログラムを理解できません。コンストラクターも演算子のオーバーロードもありません。演算子のオーバーロードとコピー コンストラクターがこのプログラムでどのように機能するかを説明してください。

編集:参照演算子を使用するのはなぜですか?

4

5 に答える 5

1

このコードにはコピーコンストラクターは含まれていませんが、コピーコンストラクターはクラスのメンバーを動的に割り当てるシナリオで使用されるため、インスタンスまたはオブジェクトがスコープ外になると、デストラクタが動的に割り当てられた割り当てを解除するため、プログラムがクラッシュしません。 newまたはmallocにそれぞれ削除または解放を含めた場合は、メモリ。

6行目で演算子のオーバーロードが発生しました:次のようなオブジェクトに追加する場合

VectorOne = VectorTwo + VectorThree;

6行目の関数が呼び出され、VectorTwoおよびVectorThreeのメンバーに加算を行う一時オブジェクトが作成され、一時オブジェクトがVectorOneに返されるため、VectorOneはTempVectorのビット単位のコピーを受け取ります。。VectorTwoはオーバーロードされた演算子の左側にあるため、この関数に暗黙的に渡されることに注意してください。のようなオブジェクトを追加するとVectorThree += VectorOne;、関数operator + =()が呼び出され、VectorThreeが暗黙的に関数に渡され、関数はビット単位のコピーを返します。関数に暗黙的に渡されるオブジェクトの。キーワードthisは、この場合はVectorThreeの関数を呼び出したオブジェクトを指します。そして、返されたコピーは再びVectorThreeに保存されます。

于 2012-07-12T17:16:03.990 に答える
1

operator+、Vector クラスの新しいインスタンスを作成し、2 つの入力の x 要素と y 要素の合計をその新しいインスタンスに入れ、新しいインスタンスを返します。少なくともIMO(そして、多くの反対意見は想像できません)は、次のように記述したほうがよいでしょう。

Vector Vector::operator+(Vector const &otherVector) const {
    // ...
}

const...どちらも変更することを意図していないため、関数自体とその右側の入力の両方を として修飾します。関数の修飾は基本的に左側のオペランドを参照するため、これは基本的に、 のようなことを行っても変更も変更もされa = b + c;ないことを示しています (つまり、通常どおりに期待されます)。これにより、(とりわけ) タイプの一時オブジェクトをオペランドとして使用できるようになり、意図せずに入力を変更しないことが保証されます。bcVector

operator+=左のオペランドを変更するため、他のベクトルの x 要素と y 要素をそれ自体に追加するだけです。次に、左オペランドとして提供されたオペランド (の修正バージョン) への参照を返します。これにより、次のような演算子の連鎖が可能になります。

Vector a, b, c;

// code to initialize a, b and c here

a += (b += c);

繰り返しになりますが、 const への参照によって入力を取得することでメリットが得られます。

Vector &Vector::operator+=(Vector const &other) {
    // ...
}

この場合、関数自体を修飾することはできません(また修飾したくありません) なぜなら、関数はその左側のオペランドを変更するからです (繰り返しますが、期待どおりです: inでは、変更され、変更されないことが期待されます)。consta += bab

少なくともあなたが示したように、クラス定義には明示的なコピー コンストラクターが含まれていません。つまり、このクラスのオブジェクトをコピーすると、コンパイラーがコピー コンストラクターを合成します。適切な状況では、クラス内のデータは 2 つの int のみであり、通常はメンバーごとのコピー (コンパイラが生成するもの) で問題ありません。明示的なコピー コンストラクターの最も一般的な理由は、それが所有するオブジェクトへの 1 つ以上のポインターを含むクラスです (この場合、3/5 の規則も確認する必要があります)。

于 2012-07-12T16:41:21.630 に答える
1
6:   Vector operator + (Vector & OtherVector);
7:   Vector & operator += (Vector & OtherVector);

それらは演算子のオーバーロードを宣言します。これらは、実際に演算子をオーバーロードすることを示すために必要です。以下の戻り値の詳細:

10: Vector Vector::operator + (Vector & OtherVector)
11: {
12:  Vector TempVector;
13:  TempVector.x = x + OtherVector.x;
14:  TempVector.y = y + OtherVector.y;
15:  return TempVector;
16: }

ベクトルの x および y コンポーネントを追加する TempVector のコピーを返します。これにより、次の使用法が可能になります (代入演算子も定義されている場合:

24: Vector VectorOne;
25: Vector VectorTwo;
26: Vector VectorThree;
27: /* Do something with vectors */
28: VectorOne = VectorTwo + VectorThree;

17: Vector & Vector::operator += (Vector & OtherVector)
18: {
19:  x += OtherVector.x;
20:  y += OtherVector.y;
21:  return * this;
22: }

これは上記と同じですが、一時変数ではなく呼び出しインスタンスに追加するというわずかな違いがあります。これにより、 が返され*thisます。thisクラスの現在のインスタンスへのポインターであるため、その値を取得するには、スター逆参照演算子を使用する必要があります (演算子の名前が間違っている場合は修正してください)。

于 2012-07-12T16:41:11.220 に答える
1

6 行目は「+」演算子をオーバーロードし、14 行目は「+=」演算子をオーバーロードしています。例えば:

Vector v1,v2,v3;

v1 += v2; // Line 14 takes care of this one

v3 = v1 + v2; // Line 6 takes care of this one

ここでの大きな違いは、'+=' オーバーロードは、演算子が呼び出されているインスタンス (上記の例では v1) 内の値を変更するのに対し、'+' 演算子は 2 つのインスタンスを取得し、変更された値で 3 番目のインスタンスを生成することです。 . これが明確であることを願っています。

于 2012-07-12T16:50:02.390 に答える
0

6 行目と 7 行目は、オーバーロードされた演算子のプロトタイプです。

Vector & operator += (Vector & OtherVector);

戻り値の型は Vector 参照で、Argument は Vector 参照です。オペレーターは+=オペレーターです。その関数は次の行で呼び出されます。

VectorThree += VectorOne;

定義は 17 行目にあります。これらが典型的なメンバー関数と同じように機能することがわかります ( thisx と y を見つけるために暗黙的に使用される定数があります)。+= 演算子の典型と同様に、この関数は引数の内容VectorOneが変更されないように機能し、 の内容はVectorThree元の値 plusVectorOneに設定され、 の新しい値VectorThreeが返されます。整数型の += 演算子が次のスニペットと同じように機能することを自分で確認できます。

int a = 1, b = 2, c;
c = (a += b);
cout << "a: " << a << " b: " << b << " c: " << c << endl;

クラスの演算子の実装は、必要な任意のモデルに従うことができることに注意することが重要です。たとえば、文字列の += 演算子はインプレース追加演算子です。一般に、クラスで + 演算子と += 演算子が定義されている場合、+ 演算子は 2 つの引数を取り、何らかの操作を実行して 3 番目の値を返し、+= 演算子は 2 つの引数を取り、何らかの操作を実行します。その引数の 1 つを変更し、その値を返します。

両方の演算子の引数の値は変更されないため、次のように const にすることができることに注意することも重要です。

Vector operator + (const Vector & OtherVector);
Vector & operator += (const Vector & OtherVector);

その理由は、引数 const を宣言していない演算子に const 変数を渡したい場合、それらが変更されていなくても渡すことができないためです。以下は、+= の引数に const が指定されていない場合は無効であり、指定されている場合は有効です。

Vector value1;
const Vector value2;

value1 += value2;
于 2012-07-12T16:42:01.967 に答える