2012-02-29 12 views
3

この問題を理解する上で問題があります。仮想課題

私はクラスを持っている:

class StringProperty { //snipped... 
protected: 
    std::string s; 
public: 
    virtual StringProperty& operator= (const std::string &x) { 
     s = x; 
     return *this; 
    } 
    virtual StringProperty& foo(const std::string &x) { 
     s = x; 
     return *this; 
    } 
}; 

(複数のメソッドを持っており、簡単にするために切り取られた)このクラスは、文字列として行動しなければなりません。

私はそれから派生:私はこのような何かやりたい

class Test : public StringProperty { }; 

Test x; 
x = "test";

はしかし、これは(コンパイルされません)、無残に失敗します。

error: no match for ‘operator=’ in ‘x = "test"’

それでも、私が使用する場合

x.foo("test");

これは機能します。 私は両方の機能が同一であるため、なぜ失敗するのかを理解することに興味があります。

ありがとうございました。

+1

'StringProperty&operator =(...)'の戻り型は、 'x =" test ";のLHS型と互換性がありません。 – Kashyap

+2

@thekashyap:オペレータは任意の型を返すことも、何も返すこともできません。連鎖を許すために '* this'を返すのは慣例に過ぎません。 –

+0

http://stackoverflow.com/questions/3410688/c-inheritance-and-operator-overloadingの重複 – jjlin

答えて

4

Testクラスには、暗黙的に宣言されたコピー代入演算子(およびデフォルトのコンストラクタ、コピーコンストラクタ、デストラクタ)が含まれています。これは、ベースクラスの1つを非表示にします。オーバーロードと見なすには、派生クラスでアクセシブルにする必要があります。

class Test : public StringProperty { 
public: 
    using StringProperty::operator=; 
}; 
+0

ありがとうございました。私は、デフォルトの方法がベースを隠していることに気づいていませんでした。 – Akobold

+0

基本クラス 'operator ='は正しいセマンティクスを持たず、スライスされます(そして派生クラスのクラスの不変条件を尊重しないオブジェクトもあります)。 'using'はすべてコンパイラを介してコードを取得します。それはまだ妥当な方法で行動しません。 –

+1

@JamesKanze:私はここにスライスがあるとは思わない。文字列からの代入は基本クラスのバージョン( 's'を修正)を使用し、' Test'への変換可能なものからの代入は暗黙の演算子を使用します。私は、 'using'が暗黙的なものを禁止していないことを確信しています(そして速いテストではそれを確認しているようですが)。 –

3

これは古典的です。

operator=は、コンパイラが作成しない特別な方法の1つです。したがって、この自動的に作成されたメソッドは、継承されたメソッドを隠します。

あなたはクラスTestに

using StringProperty::operator=; 

の行を追加して、それを解決することができます。

-1

割り当てと多型はうまく機能しません。表示されている の症状は簡単に修正できます。派生クラスのコンパイラ提供の代入演算子 は、ベースクラスの代入演算子を隠します。 これを実装する必要があります。問題は、あなたが本当にそれのために合理的なセマンティクスを提供することができないこと、しかし、 のまま:

Base* p1 = new Derived; 
Base* p2 = new Base; 
*p2 = *p1; 

は、最後の行で何が起こるのでしょうか?私は、その後、平等のいくつかの適切な定義のために、*p1 == *p2を期待しています。しかし、 “の値の一部である”が*p1の場合は、動的タイプがDerivedであるということです。 一度オブジェクトのタイプを変更することができないので、あなたはできません。 が構築されています。

(イディオムのいくつかの変形を使用して、多態的に振る舞う値タイプを作成することができ、 はまだ割り当てをサポートしています。通常は非常に遅く、通常は という価値はありません)。

+0

これは、文字列からポリモーフィックに割り当てる?私は質問との関連を見るのが難しいと思っています。 –

+0

私は一般的な課題について話していました。彼が関心を持っている特別なケースが問題の影響を受けていないことは事実です。コピーアサインにはもっと問題があります。 –

1

コピー割り当てとコピーコンストラクタは、デフォルトでTestクラス用に生成されるものです。

他の人はすでに詳しい解説で私を解決策に打ち負かしているので、私は何か他のものに集中するつもりです。

私はこのような階層的なデザインを見てきましたが、問題は本当に速くなっています。私はベーシックな数学的なベクトルライブラリを得ることができない建築家を設計しているシニア開発者と協力していました。なぜなら、彼はベクタベースクラスを作成し、そこから派生し、メンバーをサブクラスに追加し、セマンティクスのコピー基本クラス(operator =)を含む。彼は非常に素早くスライスするような問題に遭遇しました。私は、この「拡張」ファッション(スーパークラスのようなものをモデリングするサブクラス)で継承を使おうとするのをやめようと、彼に言った。このような問題は、多くの人が継承が関与しているときにオブジェクト指向の設計間違いを起こすことが多いため、C++がひどい言語(例えばLinus Torvalds)であると主張する人々のために、私はモノリシックなクラスデザインであると主張しています)。

基本クラスを介してサブクラスに与えられた割り当ての概念は、多型を破ります。犬を想像し、猫は両方にコピーセマンティクスを提供するMammalから継承します。犬を猫にコピーするとどうなりますか? Mammal &を受け取り、それにCatを割り当てている関数を呼び出してみましょう。しかし、私たちはDogへの参照を渡しました。何が起こるはずですか?それは論理的な意味を持たない。しかし、DogとCatの両方がMammalのコピー関数や演算子を使用している場合、コンパイラはこれを許可します。

このため、基本クラスをコピー不可能に設計し、仮想クローンメソッド(Prototype Pattern)のようなものを調べて、これらのデザインをすべて一緒に避けることを強くお勧めします。基底クラスは、一般に、多型を考慮した基底クラスであるために、適切かつ注意深く設計する必要があります。