C++ C++;从具有相同虚拟函数名的多个基类继承

C++ C++;从具有相同虚拟函数名的多个基类继承,c++,function,class,virtual,multiple-inheritance,C++,Function,Class,Virtual,Multiple Inheritance,我尝试了以下代码: 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

我尝试了以下代码:

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文件中


谢谢~~

您只有一个虚拟函数
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;
}

函数根据名称和参数类型重写基类的虚拟函数(请参见下文)。因此,类
C
有两个虚拟函数
foo
,分别从
A
B
继承一个。但是一个函数
void C::foo()
会覆盖这两个函数:

[class.virtual]/2

如果虚拟成员函数
vf
在类
Base
中声明,并且在直接或间接从
Base
派生的类
中声明,则声明与
Base::vf
具有相同名称、参数类型列表、cv限定和ref限定符(或不存在相同)的成员函数
vf
,然后,
Derived::vf
也是虚拟的(无论是否如此声明),它覆盖了
Base::vf

正如我在评论中已经指出的,[dcl.means]/1禁止在(成员)函数声明中使用限定id:

当声明符id被限定时,声明应引用该限定符所引用的类或命名空间的先前声明的成员[…]”

因此,任何
virtualvoid X::foo();
作为
C
中的声明都是非法的

代码

class C : public A, public B
{
    virtual void foo();
};
是AFAIK重写
foo
的唯一方法,它将同时重写
A::foo
B::foo
。对于
A::foo
B::foo
,除了引入另一层继承之外,没有其他不同行为的两种不同重写:

#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();
}
#包括
结构A
{
虚拟void foo()=0;
};
结构B
{
虚拟void foo()=0;
};
结构CA:A
{

virtual void foo(){std::cout我遇到了同样的问题,并意外地打开了第二个线程。对此感到抱歉。一种对我有效的方法是在不使用多重继承的情况下解决它

#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);
    }
};

…关于foo方法不再有任何歧义。

您可以使用不同的函数参数来解决这种歧义

在实际代码中,此类虚拟函数会执行某些操作,因此它们通常已经具有以下两种功能之一:

  • A和B中的不同参数,或
  • A和B中的不同返回值可以转换为[out]参数以解决此继承问题;否则
  • 您需要添加一些标记参数,优化器将丢弃这些参数
  • (在我自己的代码中,我通常发现自己出现在第(1)种情况下,有时出现在第(2)种情况下,到目前为止从未出现在第(3)种情况下。)

    您的示例是案例(3),如下所示:

    class A
    {
    public:
        struct tag_a { };
        virtual void foo(tag_a) = 0;
    };
    
    class B
    {
    public:
        struct tag_b { };
        virtual void foo(tag_b) = 0;
    };
    
    class C : public A, public B
    {
        void foo(tag_a) override;
        void foo(tag_b) override;
    };
    

    注释部分在gcc中也不起作用。这毫无意义。它应该是
    虚拟void foo();
    ,并且只使用一次。您希望如何使用
    A
    B
    C
    ?有许多可能性:,…(这些可能定义了比需要更多的函数)[dcl.意思]/1禁止在(成员)函数的声明中使用限定id:“当声明器id是限定的时,声明应引用限定符所引用的类或命名空间的先前声明的成员[…]”,因此任何
    virtual void X::foo();
    都是非法的(作为
    C
    中的声明)事实上,在我之前的评论中链接的代码是误导性的,因为
    C::A::foo
    实际上意味着
    A::foo
    (谢谢@DyP)。这里有一些更简单的例子:和。只是一句话:定义
    void C::A::foo(){}
    void C::B::foo(){}
    分别为纯虚拟函数
    A::foo
    B::foo
    提供定义(并且不是必需的){cout@dyp只是好奇为什么使用语法
    void C::A::foo(){}
    A::foo()提供定义是合法的
    ,使用这种语法而不是重写
    A::for(){}有什么好处吗
    直接?我看起来很困惑,如果
    A
    是一个内部类怎么办?我编译了这段代码,很惊讶它是合法的。@Dreamer这是一般概念的结果。定义成员函数时,您只需使用其中一种方法引用成员的名称;当您想要c时,也可以使用相同的引用方法所有函数,例如
    this->C::A::foo();
    名称
    A
    C
    的成员,因为类
    A
    隐式定义了一个名为
    A
    的成员,该成员引用自身(注入类名称)由于继承,这个成员
    A::A
    C
    中是可见的。如果
    CA::foo
    CB::foo
    都需要访问对象内的共享数据,那么您可能需要第三个基类来包含共享部分,然后您就得到了可怕的菱形继承。真是一团糟!请注意,abiguity可以解释为城市解析:
    c.A::foo()
    如果我把
    virtual
    放在所有
    foo
    方法之前或者只放一次,有什么区别?如果我把virtual放在方法A::foo或B::foo或CA::foo等中有关系吗?或者它是不相关的?@CătălinaSîrbu如果你显式地写
    virtual
    或者它有相同的签名,那么函数是虚拟的(名称、参数)作为任何基类中的虚拟函数。因此,此处的大多数
    virtual
    关键字都是多余的。我将
    virtual
    预先添加到所有虚拟函数(即使没有必要)以直接显示该函数是虚拟的。
    class A
    {
    public:
        struct tag_a { };
        virtual void foo(tag_a) = 0;
    };
    
    class B
    {
    public:
        struct tag_b { };
        virtual void foo(tag_b) = 0;
    };
    
    class C : public A, public B
    {
        void foo(tag_a) override;
        void foo(tag_b) override;
    };