web-dev-qa-db-ja.com

C ++は、同じ仮想関数名を持つ複数の基本クラスから継承します

私はこのコードを試しました:

class A
{
    virtual void foo() = 0;
};

class B
{
    virtual void foo() = 0;
};

class C : public A, public B
{
    //virtual void A::foo(){}
    //virtual void B::foo(){}

    virtual void A::foo();
    virtual void B::foo();
};

void C::A::foo(){}
void C::B::foo(){}

int main()
{
    C c;
    return 0;
}

コメント部分を使用する場合は問題ありませんが、クラス宣言の外部に定義を書き込もうとすると、コンパイラーがエラーを報告します。私はMSVC11コンパイラを使用していますが、これを書く方法を知っている人はいますか?コードをcppファイルに移動する必要があります。

ありがとう~~

15
watson

関数は、名前とパラメータータイプに基づいて、基本クラスの仮想関数をオーバーライドします(以下を参照)。したがって、クラスCにはtwo仮想関数fooがあり、1つは各ABから継承されます。ただし、関数void C::foo()両方をオーバーライドします:

[class.virtual]/2

仮想メンバー関数vfがクラスBaseおよびクラスDerivedで宣言され、Baseから直接または間接的に派生した場合、同じ名前のメンバー関数vfparameter-type-list、cv-qualification 、および_Base::vf_としてのref-qualifier(または同じものがない)が宣言されている場合、_Derived::vf_も仮想(宣言されているかどうかに関係なく)であり、オーバーライド _Base::vf_。

コメントですでに述べたように、[dcl.meaning]/1は、(メンバー)関数の宣言でqualified-idを使用することを禁じています。

declarator-idが修飾されている場合、宣言は、修飾子が参照するクラスまたは名前空間の以前に宣言されたメンバーを参照するものとします[...] "

したがって、virtual void X::foo();C内の宣言としては違法です。

コード

_class C : public A, public B
{
    virtual void foo();
};
_

aFAIKがfooをオーバーライドする唯一の方法であり、_A::foo_と_B::foo_の両方をオーバーライドします。 _A::foo_と_B::foo_に2つの異なるオーバーライドを設定して、別の継承レイヤーを導入する以外に、動作を変える方法はありません。

_#include <iostream>

struct A
{
    virtual void foo() = 0;
};

struct B
{
    virtual void foo() = 0;
};

struct CA : A
{
    virtual void foo() { std::cout << "A" << std::endl; }
};

struct CB : B
{
    virtual void foo() { std::cout << "B" << std::endl; }
};

struct C : CA, CB {};

int main() {
    C c;
    //c.foo();  // ambiguous

    A& a = c;
    a.foo();

    B& b = c;
    b.foo();
}
_
21
dyp

仮想関数は1つだけですfoo

class A {
    virtual void foo() = 0;
};

class B {
    virtual void foo() = 0;
};

class C : public A, public B {
    virtual void foo();

};

void C::foo(){}
void C::A::foo(){}
void C::B::foo(){};

int main() {
    C c;
    return 0;
}
4
Paul Evans

私は同じ問題に踏み込み、誤って2番目のスレッドを開きました。そのために残念。私のために働いた1つの方法は、多重継承なしでそれを解決することでした。

#include <stdio.h>

class A
{
public:
    virtual void foo(void) = 0;
};

class B
{
public:
    virtual void foo(void) = 0;
};


class C
{
    class IA: public A
    {
        virtual void foo(void)
        {
            printf("IA::foo()\r\n");
        }
    };
    class IB: public B
    {
        virtual void foo(void)
        {
            printf("IB::foo()\r\n");
        }
    };

    IA m_A;
    IB m_B;
public:
    A* GetA(void)
    {
        return(&m_A);
    }

    B* GetB(void)
    {
        return(&m_B);
    }
};

秘訣は、多重継承を使用するのではなく、インターフェイス(AおよびB)から派生したクラスをローカルクラス(IAおよびIB)として定義することです。さらに、このアプローチは、必要に応じて、多重継承を使用して不可能な、各インターフェースの複数の実現を持つオプションも開きます。ローカルクラスIAとIBは、クラスCへのアクセスを簡単に許可できるため、インターフェイスIAとIBの両方の実装でデータを共有できます。

各インターフェイスへのアクセスは、次のように実行できます。

main()
{
    C test;
    test.GetA()->foo();
    test.GetB()->foo();
}

...そしてfooメソッドに関するあいまいさはもうありません。

0
TLI123