2011-07-17 8 views
16

C++の継承に問題があります。C++仮想関数が隠されています

私はクラスの階層構造を持っている:

class A { 
public: 
    virtual void onFoo() {} 
    virtual void onFoo(int i) {} 
}; 

class B : public A { 
public: 
    virtual void onFoo(int i) {} 
}; 

class C : public B { 
}; 


int main() { 
    C* c = new C(); 
    c->onFoo(); //Compile error - doesn't exist 
} 

私の質問は:なぜこれはコンパイルされませんか?私の理解は、CはonFoo関数をAから継承する必要があり、実際にはBのonFooの再定義を削除するとコンパイルされますが、g ++はCにonFoo()関数がないというエラーを返します。

答えて

33

問題は、名前の検索がC++でどのように機能するかに関係しています。特に、メンバーを解決するとき、コンパイラーは、メンバーがアクセスされているオブジェクトの静的タイプを調べます。そのクラスで識別子が見つかった場合は、ルックアップが完了し、(メンバー関数の場合)オーバーロード解決が開始されます。識別子が見つからない場合は、階級別に階層をクロールし、一度に識別子を見つけようとします。

具体的にはc->onFoo();cCです。コンパイラはonFooの宣言をCに表示しないため、階層の上に移動します。コンパイラがBをチェックすると、そのレベルにvoid onFoo(int i)の宣言があることがわかります。そのため、参照が停止され、オーバーロードの解決が試行されます。現時点では、引数の不一致により、オーバーロードの解決に失敗します。

void onFoo(int)の宣言はBレベルで存在するという事実は、それがルックアップを停止するように、任意の基底クラスでオーバーロードの残りの部分を隠蔽効果を有します。これは非修飾ルックアップの問題であることに注意してください。関数はまだそこにあり、オブジェクトに適用できますが、通常のルックアップでは見つかりません(まだc->A::onFoo()と呼びます)。を隠すに対処する方法として

、最も簡単な方法は、スコープ内の機能をもたらすために使用して宣言を使用することによってである:

class B : A { 
public: 
    using A::onFoo; // All A::onFoo overloads are *considered* here 
    void onFoo(int); 
}; 

ここusing宣言の効果は、そのときBクラスでありますコンパイラはonFoo識別子を検索して、ベースクラスのonFooのすべてのオーバーロードを考慮し、通常の検索でA::onFoo()を検索するように指示されます。

+0

+1 - いい説明。 – Mahesh

7

これは名前の隠蔽です。基本的にはBに宣言されたオーバーライドのみが存在し、Aの他のオーバーロードは非表示になっています。

2

クラスAとクラスBのメソッドは公開する必要があります。それと、クラス宣言の最後にセミコロンがありません。

+0

これらは有効な点ですが、「修正」もコンパイルされません。 –

1
class A { 
public: 
    virtual void onFoo() {} 
    virtual void onFoo(int i) {} 
}; 

class B : public A { 
public: 
    virtual void onFoo(int i) {} 
}; 

class C : public B { 
}; 


int main() { 
    C* c = new C(); 
    c->onFoo(); //Compile error - doesn't exist 
} 

そのため、メソッドonFooどこでもこれらのクラス外可視プライベートしたがってないクラスAおよびBの両方のメソッド前public:修飾子を忘れてしまいました。

+0

おっと、 - それは問題ではなかった、それは私が問題を間違って転記したことでした。修正するために編集しました –

12

あなたが派生クラスのメンバーをオーバーロードするために、基本クラスのメンバを使用する場合は、あなたがusingを使用する:あなたが経験している

struct A 
{ 
    virtual void onFoo() {} 
    virtual void onFoo(int i) {} 
}; 

struct B : A 
{ 
    using A::onFoo; 
    virtual void onFoo(int i) {} 
}; 

struct C : B 
{ 
}; 


int main() 
{ 
    C* c = new C(); 
    c->onFoo(); 
} 
-2

私はあなたがclass Bでこれを追加見逃していると思います:

struct B : A 
{ 
    using A::onFoo; 
    virtual void onFoo(int i) {} 
    void onFoo() {} //This line missing in your code. 
}; 

さて、これはコンパイル!

関連する問題