13
#include <iostream>
struct B1
{
    virtual void method()=0;
    virtual ~B1(){}
};

struct B2
{
    virtual void method()=0;
    virtual ~B2(){}
};

struct D: B1, B2
{
    virtual void method()
    {
        std::cout << "D::method\n";
    };
};

int main(int argc,char *argv[])
{
    D d;
    B1 &b1=d;
    B2 &b2=d;
    b1.method();
    b2.method();
    return 0;
}

B1 と B2 は共通のインターフェースを共有しないことに注意してください。

これは合法ですか?はいの場合 - どの規格で?C++98/03/11 ?

msvc と gcc の両方が正常にコンパイルされました。

以前は、そのような場合(仮想継承の可能性)には共通のインターフェースを使用する必要があると考えていました。

そのような状況には特別な名前がありますか?

詳細な仕組みを教えてください。多分いくつかのISO参照?

4

2 に答える 2

7

あなたのコードは整形式です: と の両方をvoid D::method()オーバーライドします。void B1::method()void B2::method()

仕様には次のように記載されています (C++11 §10.3/2):

仮想メンバー関数が classおよびvfclass で宣言され、から直接的または間接的に派生した場合、同じ名前、parameter-type-list、cv-qualification、および ref-qualifier (または同じものがない) を持つメンバー関数が宣言されている場合は、(そう宣言されているかどうかに関係なく) 仮想でもあり、 をオーバーライドします。BaseDerivedBasevfBase::vfDerived::vfBase::vf

B1仮想メンバー関数を宣言しますvoid B1::method()。クラスDはから派生し、同じ名前 ( )、同じパラメーター リスト (パラメーターなし)、同じ cv-qualification (修飾なし)、および同じ ref-qualifier (修飾なし) をB1持つメンバー関数も宣言します。method

したがって、void D::method()オーバーライドしますvoid B1::method()

同じロジックが for に適用されます(上記の説明でforをvoid B2::method()置き換えるだけです)。そのため、 と の両方をオーバーライドします。B2B1void D::method()void B1::method()void B2::method()

于 2012-07-12T20:41:42.583 に答える
1

これはすべての基準で合法です。独自の特別な名前があるかどうかはわかりませんが、ダイヤモンドの問題に似ています。

D で「virtual void method()」をオーバーライドすると、B1 と B2 の両方のメソッドがオーバーライドされます。

編集:

「D に 2 つの異なる独立した継承された仮想関数: B1::method と B2::method」がない理由を説明するには:

メソッドをオーバーライドするときは、関数名、戻り値の型、およびパラメーターのみを指定できますが、オーバーライド時に継承するメソッドに関する署名の詳細を追加することはできません。

それが可能であると想像すると、次のようになります。

struct D: B1, B2
{
    virtual void B1::method()
    {
        std::cout << "D::method\n";
    };
    virtual void B2::method()
    {
        std::cout << "D::method\n";
    };
};

しかし、これを見ると、そのようなものを持つ可能性はないとすでに言えます。

objectD.method()

どちらを呼び出しているかを指定することはできません。したがって、両方をオーバーロードする方法があったとしても、関数呼び出しで区別するという問題がまだあります。

編集: 「あなたが呼んでいるものを指定することはできません。」を参照すると、B2::method のクラス D オーバーロードを呼び出すか、B2 メソッド自体を呼び出すかを指定できません。objectD.B2::method は常に B2 (オーバーロードされていない) メソッドを呼び出します (この場合、B2 には実装がないためコンパイルされません)。

于 2012-07-12T20:07:33.207 に答える