2012-01-15 6 views
3

私はこの動作を理解しようとしていますが、私はそうではないようです。このコードを参照してください。派生クラスは、基底の代入演算子を間接的に継承しますか?

#include <iostream> 
using namespace std; 

class Base 
{ 
public: 
    void operator=(const Base& rf) 
    { 
     cout << "base operator=" << endl; 
     this->y = rf.y; 
    } 
    int y; 
    Base() : y(100) { } 
}; 

class Derived : public Base 
{ 
public: 
    int x; 
    Derived() : x(100) { } 
}; 

int main() 
{ 
    Derived test; 
    Derived test2; 
    test2.x = 0; 
    test2.y = 0; 
    test.operator=(test2); // operator auto-generated for derived class but... 
    cout << test.x << endl << test.y << endl; 
    cin.ignore(); 
    return 0; 
} 

プログラムの出力:

> base operator= 
> 0 
> 0 

今、私は混乱しているです: ルールは派生クラスは、assigment演算子を継承することはありません代わりに、それは、独自に作成することを言いますoperator=ただし、この例では、基底クラスのoperator=が呼び出されます。

第2に、派生クラスで明示的に定義されていない派生クラスに対して明示的に譲渡演算子を呼び出すことができました。

これを正しく理解すれば、ユーザー定義ベースの演算子は常に派生クラスで呼び出されることを意味しますか?

答えて

12

生成されたものが自動的にベースクラスの代入演算子を呼び出します。

// generated version looks basically like this 
Derived& operator=(Derived const& other){ 
    Base::operator=(static_cast<Base const&>(other)); 
    x = other.x; 
    return *this; 
} 

キャストはこのようなテンプレートBase::operator=にaccidentialの呼び出しを回避することがあります:

template<class Other> 
Base& operator=(Other const& other); // accepts everything 

またはこのような奇妙な1:

// forward-declare 'Derived' outside of 'Base' 
Base& operator=(Derived const& other); // accepts derived class (for whatever reason) 

第二に、私は明示的に譲渡の際に譲渡オペレータを呼び出すことができましたdクラスであり、派生クラスで明示的に定義されていません。あなたが実際にどこかでそれを使用する場合

そうしないと、あなたのクラスは、それ(すなわち、無基準部材と他のいくつかの難解なルール)許可する場合、コンパイラが自動的に代入演算子を宣言し、さらにそれを定義しています。

4

コンパイラ生成の代入演算子は、各サブオブジェクトの代入演算子を呼び出します。これには、基本クラスと非静的メンバー変数が含まれます。

標準は(セクション12.8 [class.copy])言う:

クラスデFi回線nitionは、明示的にコピー代入演算子、1が暗黙的に宣言された宣言しない場合。クラス定義が移動コンストラクタまたは移動代入演算子を宣言する場合、暗黙的に宣言されたコピー代入演算子は削除済みと定義されます。それ以外の場合は、デフォルト(8.4)として定義されます。後者の場合は、クラスにユーザ宣言されたコピーコンストラクタまたはユーザ宣言されたデストラクタがある場合は非推奨になります。クラスXための暗黙的に宣言されたコピー代入演算子は、 const volatile B&

  • それぞれ直接ベースクラスXBパラメータタイプconst B&であるコピー代入演算子を有する

    X& X::operator=(const X&) 
    

    場合形状を有することになりますまたはBおよび

  • Xのすべての非静的データメンバーについては、クラスタイプM(または配列そのようなクラス型の各々は、パラメータがconst M&,const volatile M&またはMのコピー代入演算子を有する。

そうでない場合は、暗黙的に宣言されたコピー代入演算子は、フォームを持っています

X& X::operator=(X&) 

非組合クラスの暗黙的に定義されたコピー/移動代入演算子Xは、そのサブオブジェクトのメンバー単位のコピー/移動割り当てを実行します。 Xの直接基底クラスが、ベース指定子リストの宣言の順番で最初に割り当てられ、次に直接的な非静的データメンバーXが、それらが宣言された順に割り当てられますクラス定義。xを関数 のパラメータ、または移動演算子の場合はそのパラメータを参照するxvalueとします。各サブオブジェクトは、その種類に適切な方法で割り当てられている:

  • サブオブジェクトは、オブジェクト表現と単一の機能としてxの対応するサブオブジェクトとしてサブオブジェクトとoperator=に呼び出したかのように、クラスタイプである場合(派生クラスの仮想オーバーライド関数を無視して明示的に指定するかのように)
  • サブオブジェクトが配列の場合、要素の種類に応じて各要素が割り当てられます。
  • サブオブジェクトがスカラー型の場合は、組み込みの代入演算子が使用されます。

仮想基本クラスを表すサブオブジェクトが、暗黙的に定義されたコピー代入演算子によって複数回割り当てられているかどうかは不明です。

+0

これは、ユーザ定義演算子がサブオブジェクトの演算子を呼び出さないことを意味しますか?コンパイラが生成した演算子コールのサブオブジェクトの演算子のみがそうであると言っていますか? – codekiddy

+1

@codekiddy:基本クラスのバージョンを自分で呼び出すのでなければ、コンパイラはあなたのためにそれをしません。 – Xeo

+0

非常にverryありがとう! – codekiddy

2

これは、暗黙的に定義された演算子=が基本クラスoperator =を呼び出すためです。

I'm creating a derived class; should my assignment operator call my base class's assignment operator?

はい(あなたが最初の場所での代入演算子を定義する必要がある場合):よくある質問ライトを参照してください。

独自の代入演算子を定義すると、コンパイラは自動的に基本クラスの代入演算子を呼び出しません。基本クラスの代入演算子自体が壊れていない限り、派生クラスの代入演算子から明示的に呼び出す必要があります(最初は、代入演算子を作成すると仮定します)。

しかし、あなたがあなた自身の代入演算子、あなたは自動的にあなたの基本クラスの代入演算子を呼び出しますため、コンパイラが作成したものを作成しない場合。

+0

ありがとう、それはverry有用だった! – codekiddy

-1

4物事は決してはコンストラクタ コピーコンストラクタ デストラクタ

もあなたがあなたのコードは、ウォーキングの罰金になります代入演算子を書いていない 代入演算子 継承されます。 代入演算子compilerを使用するたびに、各メンバーオブジェクトと基本クラスの代入演算子が呼び出されることを確認します。

+0

これは真実ではない、私の答えの下のコメントを見てください。 –

+0

@ベン - 私はすべてのことを解明していないかもしれません。私はコンパイラが提供する機能について話していました。 – Amit

関連する問題