2012-04-24 15 views
10

私は、コードのこの部分を試してみた:多重継承:2Classes1Method

struct FaceOfPast 
{ 
    virtual void Smile() = 0; 
}; 

struct FaceOfFuture 
{ 
    virtual void Smile() = 0; 
}; 

struct Janus : public FaceOfPast, public FaceOfFuture 
{ 
    virtual void Smile() {printf(":) ");} 
}; 

...

void main() 
{ 
    Janus* j = new Janus(); 
    FaceOfFuture* future = j; 
    FaceOfPast* past = j; 

    future->Smile(); 
    past->Smile(); 

    delete j; 
} 

をそれが意図した(出力2スマイリーフェイス)として動作しますが、私はしないでくださいコンパイルすべきだと思うが、JanusSmile()の再宣言はあいまいである。

どのように動作しますか?

答えて

7

FaceOfFutureFaceOfPastへのポインタにSmile()を呼び出し、1つのメソッドSmile()しか宣言していないため、曖昧さはありません。

基底クラスのポインタでメソッドを呼び出すと、曖昧になることができないので、あなたは直接の子クラスポインタ上のメソッドを呼び出すときのは、状況を扱うみましょう:

Janus* j = new Janus(); 
j->Smile(); 

派生クラス、オーバーライドの他に、基本クラスの宣言であるSmile()も隠します。

次のコンパイル:

struct FaceOfPast 
{ 
    virtual void Smile() {printf(":) ");} 
}; 
struct FaceOfFuture 
{ 
    virtual void Smile() {printf(":) ");} 
}; 
struct Janus : public FaceOfPast, public FaceOfFuture 
{ 
    virtual void Smile() {printf(":) ");} 
}; 
int main() 
{ 
    Janus* j = new Janus(); 
    j->Smile(); 
} 

あなたはJanusSmileを呼び出しますが、基本クラスの宣言が隠されているあなたは、あなたの派生クラスのメソッドをオーバーライドされない場合にのみ、あいまいさを持っていると思います。

次はしていません:

struct FaceOfPast 
{ 
    virtual void Smile() {printf(":) ");} 
}; 

struct FaceOfFuture 
{ 
    virtual void Smile() {printf(":) ");} 
}; 

struct Janus : public FaceOfPast, public FaceOfFuture 
{ 
}; 

int main() 
{ 
    Janus* j = new Janus(); 
    j->Smile(); 
} 

ので曖昧で。

+2

質問は、呼び出し側の部分ではないようですが、再定義の部分:なぜ、2つの異なるクラスから同じ名前の2つの仮想メソッドを再定義できますか? – alexisdm

0
Janus* j = new Janus(); 
FaceOfFuture* future = j; 
FaceOfPast* past = j; 

このセクションでは、基本クラスにキャストダウンします。あなたが次のことをするとき

future->Smile(); 
past->Smile(); 

これは実際FaceofPastとFaceOfFutureへのポインタです。

1

C++標準(10.3.2)によれば、仮想メンバ関数VFがクラスベースおよび派生クラスで宣言されている場合

を、ベースから直接的または間接的に誘導されます、メンバ関数vfと同じ名前、パラメータタイプリスト、cv-qualification、およびref-qualifier(または同じものがない)Base :: vfが宣言され、Derived :: vf [ ...]オーバーライドBase :: vf

それはおそらくここにも適用されますので、多重継承のための特別な処理があるように思えません:すべての曖昧さなしvoid Janus::Smile()オーバーライド両方の方法それは両方の基底クラスとまったく同じ名前とシグネチャを持っているという理由だけで、メソッド。