多重継承で重複するメンバ関数をオーバーライド

http://www.geocities.jp/ky_webid/cpp/language/033.html

多重継承とは複数のクラスをスーパークラスとして持つことです。

もしスーパークラスとなるクラス同士でまったく同じ宣言の関数があった場合、問題が起きます。

#include <iostream>
using namespace std;

class CSuper1 {
public:
    void Foo () { cout << "CSuper1::Foo" << endl; }
};

class CSuper2 {
public:
    void Foo () { cout << "CSuper2::Foo" << endl; }
};

class CSub : public CSuper1, public CSuper2 {
public:
};

int main() {
    CSub obj;
    
    // CSuper1のFoo?CSuper2のFoo?
    obj.Foo();
    
    return 0;
}

CSuper1にもCSuper2にも同じ定義のFoo関数が存在しています。

この場合「obj.Foo()」はどちらのFoo関数を呼び出せば良いのか判断が付きません。

なのでこの書き方はコンパイルエラーとなります。

main.cpp
main.cpp(25) : error C2385: 'Foo' へのアクセスがあいまいです。
        'Foo' (ベース 'CSuper1' 内) である可能性があります
        または、'Foo' (ベース 'CSuper2' 内) である可能性があります
main.cpp(25) : error C3861: 'Foo': 識別子が見つかりませんでした

これを回避するために、どちらのFoo関数なのかを明示的に書く方法があります。

int main() {
    CSub obj;
    
    obj.CSuper1::Foo();
    obj.CSuper2::Foo();
    
    return 0;
}
$ main
CSuper1::Foo
CSuper2::Foo

ただしこの書き方は、コンパイルの時点で呼び出す関数が決定してしまっているので多態性を実現できません。

次に仮想関数が同じだった場合のことを想定してみます。

#include <iostream>
using namespace std;

class CSuper1 {
public:
    virtual void Foo () { cout << "CSuper1::Foo" << endl; }
    void call () { Foo(); }
};

class CSuper2 {
public:
    virtual void Foo () { cout << "CSuper2::Foo" << endl; }
    void call () { Foo(); }
};

class CSub : public CSuper1, public CSuper2 {
public:
    void Foo () { cout << "CSub::Foo" << endl; }
};

int main() {
    CSub obj;
    
    obj.CSuper1::call();
    obj.CSuper2::call();
    
    return 0;
}
$ main
CSub::Foo
CSub::Foo

となります。

うまくオーバーライドは出来ていますが、CSuper1とCSuper2で別の振る舞いをさせることはできません。

関数名が同じなのでCSuper1のFooとCSuper2のFooを別々にオーバーライドすることができないということになります。

そもそも同じ名前の仮想関数な時点でそーゆーことをやろうとしてること自体間違えているとは思いますが。