あいまいな仮想関数呼び出し

C++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() を許可しません。

関連参照

IBM Copyright 2003