1 つの仮想関数を、2 つ以上のあいまいな仮想関数でオーバーライドすることはできません。
これは、仮想基底クラスから派生した 2 つの非仮想基底から継承する派生クラスで
発生する可能性があります。
次に例を示します。
class V { public: virtual void f() { } }; class A : virtual public V { void f() { } }; class B : virtual public V { void f() { } }; // Error: // Both A::f() and B::f() try to override V::f() class D : public A, public B { }; int main() { D d; V* vptr = &d; // which f(), A::f() or B::f()? vptr->f(); }
コンパイラーは、クラス D の定義を許可しません。 クラス A では、A::f() のみが V::f() をオーバーライドします。 同様にクラス B でも、B::f() のみが V::f() をオーバーライドします。 ただし、クラス D では、A::f() と B::f() の両方が、V::f() をオーバーライドしようとします。 上記の例で示すように、D オブジェクトが、 クラス V を指すポインターを使用して参照される場合、 コンパイラーは、どちらの関数を呼び出すべきかを決めることができないので、このような試みは許されません。 1 つの関数のみが仮想関数をオーバーライドできます。
同じクラス型の別個のインスタンスがあることによって、 仮想関数のあいまいなオーバーライドが起きた場合、特殊なケースになります。 次の例では、クラス D には、クラス A の 2 つの別々のサブオブジェクトがあります。
#include <iostream> using namespace std; struct A { virtual void f() { cout << "A::f()" << endl; }; }; struct B : A { void f() { cout << "B::f()" << endl;}; }; struct C : A { void f() { cout << "C::f()" << endl;}; }; struct D : B, C { }; int main() { D d; B* bp = &d; A* ap = bp; D* dp = &d; ap->f(); // dp->f(); }
クラス D にはクラス A のオカレンスが 2 つあり、1 つは B から継承されたもので、 もう 1 つは C から継承されたものです。 したがって、仮想関数 A::f にも 2 つのオカレンスがあります。 ステートメント ap->f() は D::B::f を呼び出します。 ただし、コンパイラーは D::B::f または D::C::f のいずれも呼び出すことができるので、 ステートメント dp->f() を許可しません。
関連参照