Emjayen
Emjayen

Reputation: 147

Multiple virtual inheritance ambiguity

Probably best explained with an example:

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


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


struct C : A, B
{
    // Implementation of A::foo
    void A::foo();

    // Implementation of B::foo
    void B::foo();
};


// Define here; howto?

I'm aware I can define the functions inline with the class however that's not feasible in this instance (there are about 6 base classes to implement all with 40+ methods)

--

Apparently I wasn't clear enough. The question directly is: How to define both foo() methods that have been inherited without causing ambiguity issues?

The following does indeed work

void C::foo() { /* etc */ } 

This will define the implementation of A::foo() yet what of B::foo() ? Bearing in mind I do not wish to define the methods within the declaration of C.

P.S., the reason for modelling the problem this way at all is predefined (COM/OLE)

--

This is fine (MSVC) albeit inline:

struct A { virtual int foo() = 0; };
struct B { virtual int foo() = 0; };

struct C : A, B
{
    int A::foo() { return 1; }
    int B::foo() { return 2; }
};


void main()
{
    C* p = new C();

    cout << ((A*) p)->foo();
    cout << ((B*) p)->foo();
}

Upvotes: 0

Views: 626

Answers (2)

Mike Seymour
Mike Seymour

Reputation: 254431

You can't provide separate overrides for two functions with the same signature defined in two base classes. (You can't define them inline within the class either, as you seem to think).

One possibility is to introduce intermediate base classes to rename the functions:

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

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

struct C : ABodge, BBodge
{
    void A_foo();
    void B_foo();
};

Alternatively, you could avoid multiple inheritance by composing two internal classes, each of which implement one of the base class interfaces:

class C
{
public:
    // Could probably be defined as `operator A&()`, etc. to look more like
    // inheritance, but I usually prefer conversions to be explicit.
    A       & asA()       {return a;}
    A const & asA() const {return a;}
    B       & asB()       {return b;}
    B const & asB() const {return b;}

private:
    // These might need back-references to the 'C' that contains them.
    struct AImpl : A {void foo();} a;
    struct BImpl : B {void foo();} b;
};

Upvotes: 4

Kerrek SB
Kerrek SB

Reputation: 476990

Works as expected:

struct A { virtual void foo() = 0; };
struct B { virtual void foo() = 0; };
struct C : A, B { virtual void foo(); };
void C::foo() { }

For any C x;, static_cast<A&>(x).foo() and static_cast<B&>(x).foo() will call x.foo() as expected, which is precisely what the pure-virtual interfaces of A and B promise.

Upvotes: 1

Related Questions