2009-12-02 22 views
7

私は理解できない問題に遭遇しましたが、ここの誰かがある程度の洞察を提供することを望んでいました。次のように単純化されたコードは、(元のコードは、カスタムキュー/キュー・イテレータの実装だった)です:参照メンバーを持つ内部クラスのデフォルト代入演算子

class B 
{ 
public: 
    B() {}; 
    class C 
    { 
    public: 
     int get(); 
     C(B&b) : b(b){}; 
    private: 
     B& b; 
    }; 
public: 
    C get_c() { return C(*this); } 
}; 

int main() 
{ 
    B b; 
    B::C c = b.get_c(); 


    c = b.get_c(); 
    return EXIT_SUCCESS; 
} 

これ、コンパイルされたときに、私は次のエラーを与える:

foo.cpp: In member function 'B::C& B::C::operator=(const B::C&)': 
foo.cpp:46: error: non-static reference member 'B& B::C::b', can't use default assignment operator 
foo.cpp: In function 'int main()': 
foo.cpp:63: note: synthesized method 'B::C& B::C::operator=(const B::C&)' first required here 

私はこの周りに行くことができます独立した 'C'オブジェクトであるはずの2つの独立したC変数を使用することで、問題を隠すだけです(なぜ私はこれを行うことができないのかまだ分かりません)。

私はその理由は、参照をコピーすることはできないと思うが、なぜ私は理解していない。私自身の代入演算子とコピーコンストラクタを用意する必要がありますか?

答えて

13

この問題は、内部クラスとは関係ありません。 C++では、参照を割り当てる(再)ことはできません - 定義されたときに初期化する必要があります。

シンプルな例は次のとおりです。

class B 
{ 
public: 
    B(int& i) : ir(i) {}; 

    int& ir; 
}; 


int main() 
{ 
    int i; 
    B b(i);  // Constructor - OK 

    int j; 
    B bb = B(j); // Copy constructor - OK 

    bb = b;  // Assignment - Error 
    return 0; 
} 
+0

バー、もちろんあなたは正しいです、私は明らかな説明を逃したとは思えません。朝にもっとコーヒーを持っていたはずです:D – laura

+2

+1。私は習慣的に参照を話すときに私がこのミスをするのを助けるときに "割り当て"ではなく "バインド"を使用することがわかります。 –

+0

今、私は参照を再割り当てしようとしていますが、もちろんそれはコンパイルされます:int a = 3; int b = 4; int&ref = a; ref = b;したがって、参照を再割り当てすることは可能です。 – friko

6

初期値が与えられてから参照を変更することはできません。つまり、参照メンバの値を変更する代入演算子を記述することは不可能です。これを行う必要がある場合は、参照の代わりにポインタを使用します。

+0

実際には可能です。詳細は下記の私のコメントをチェックしてください。 – rmn

0

C++は "内部クラス"、ちょうど入れ子になったクラス宣言を持っていません。 「内部クラス」は、私が他の主流言語ではないと考えるJavaのアイムです。 Javaでは、内部クラスは、包含する型のオブジェクトへの暗黙の不変参照を含んでいるため、特殊です。 JavaでのC++のネスト宣言と同等の処理を実現するには、静的内部クラスの使用が必要です。静的内部クラスには、宣言型のオブジェクトへの参照が含まれていません。

3

実際、これに対する解決策があります。あなたはimplement operator= in terms of copy constructionとすることができます:)それはこのような場合のための非常に有能なテクニックです。割り当てをサポートしたいと仮定します。

+1

代入演算子でデストラクタを呼び出すことは、非常に悪いプログラミング習慣です。 – Sjoerd

+1

まず、あなたの答えをありがとう、私は自分自身でこのソリューションに達していたが、自己割り当てチェックと明示的なデストラクタコールを省いた。このような欠点があるとすれば、それを使用することをお勧めしません(私はあなたの推論に同意します)。 – dukedave

関連する問題