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

C++ inherit from multiple base classes with the same virtual function name

本文关键字:继承 基类 函数 虚拟 C++      更新时间:2023-10-16

我试过这个代码:

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

谢谢~~

函数基于名称和参数类型覆盖基类的虚拟函数(请参见下文)。因此,类C具有两个虚拟函数foo,它们分别继承自AB。但是函数void C::foo()覆盖both:

[class.virtual]/2

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

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

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

因此,任何virtual void X::foo();作为C内部的声明都是非法的。

代码

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

是AFAIK覆盖foo的唯一方法,它将覆盖A::fooB::foo。除了引入另一层继承:之外,没有办法对具有不同行为的A::fooB::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();
}

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

我遇到了同样的问题,意外地打开了第二个线程。抱歉。对我有效的一种方法是在没有多重继承的情况下解决它。

#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()rn");
        }
    };
    class IB: public B
    {
        virtual void foo(void)
        {
            printf("IB::foo()rn");
        }
    };
    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方法不再存在歧义。

您可以使用不同的函数参数来解决这种模糊性。

在现实世界的代码中,这样的虚拟函数会起作用,所以它们通常已经有了以下两种:

  1. A和B中的不同参数,或
  2. A和B中的不同返回值,可以将其转换为[out]参数,以解决此继承问题;否则
  3. 您需要添加一些标记参数,优化器会丢弃这些参数

(在我自己的代码中,我通常发现自己处于情况(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;
};

与adigostin的解决方案相比略有改进:


#include <iostream>
struct A {
    virtual void foo() = 0;
};
struct B {
    virtual void foo() = 0;
};
template <class T> struct Tagger : T {
    struct tag {};
    void foo() final { foo({}); }
    virtual void foo(tag) = 0;
};
using A2 = Tagger<A>;
using B2 = Tagger<B>;
struct C : public A2, public B2 {
    void foo(A2::tag) override { std::cout << "A" << std::endl; }
    void foo(B2::tag) override { std::cout << "B" << std::endl; }
};
int main() {
    C c;
    A* pa = &c;
    B* pb = &c;
    pa->foo(); // A
    pb->foo(); // B
    return 0;
}

假设基类CCD_ 22和CCD_。