C++ inherit from multiple base classes with the sa

2019-01-07 00:36发布

问题:

I tried this code:

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

It is OK when using the commented part, but when I try to write the definitions outside the class declaration, the compiler reports errors. I am using the MSVC11 compiler, does anyone know how to write this? I need to move the code into the cpp file.

Thank you~~

回答1:

A function overrides a virtual function of a base class based on the name and parameter types (see below). Therefore, your class C has two virtual functions foo, one inherited from each A and B. But a function void C::foo() overrides both:

[class.virtual]/2

If a virtual member function vf is declared in a class Base and in a class Derived, derived directly or indirectly from Base, a member function vf with the same name, parameter-type-list, cv-qualification, and ref-qualifier (or absence of same) as Base::vf is declared, then Derived::vf is also virtual (whether or not it is so declared) and it overrides Base::vf.

As I already stated in the comments, [dcl.meaning]/1 forbids the use of a qualified-id in the declaration of a (member) function:

When the declarator-id is qualified, the declaration shall refer to a previously declared member of the class or namespace to which the qualifier refers [...]"

Therefore any virtual void X::foo(); is illegal as a declaration inside C.

The code

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

is the only way AFAIK to override foo, and it will override both A::foo and B::foo. There is no way to have two different overrides for A::foo and B::foo with different behaviour other than by introducing another layer of inheritance:

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


回答2:

You've got just one virtual function 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;
}


回答3:

I stepped into the same problem and accidentially opened a second thread. Sorry for that. One way that worked for me was to solve it without multiple inheritance.

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

The trick is to define classes derived from the interfaces (A and B) as local classes (IA and IB) instead of using multiple inheritance. Furthermore this approach also opens the option to have multiple realizations of each interface if desired which would not be possible using multiple inheritance. The local classes IA and IB can be easily given access to class C, so the implementations of both interfaces IA and IB can share data.

Access of each interface can be done as follows:

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

... and there is no ambiguity regarding the foo method any more.