简体   繁体   中英

Diamond (multiple inheritance) with no data members

Suppose we have the usual diamond-pattern:

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

    virtual ~A() {} 
};

class B :  public A
{
public:
    virtual char foo() { return 'B';}

    virtual ~B() {}
};

class C :  public A
{
public:
    virtual char foo() { return 'C';}

    virtual ~C() {}
};

class D :  public B,  public C
{
public:

    virtual char foo() { return 'D';}

    virtual ~D() {}
};

Please note that the base class A does not have any data members. It's in fact just an interface with pure virtual methods.

Now if i do:

D* d = new D();

A* a = static_cast<A*>(d);

the compiler will tell me that the cast is ambiguous as there are two A base classes.

But what if i do:

D* d = new D();

B* b = static_cast<B*>(d); // Or C* c = static_cast<C*>(d); 

A* a = static_cast<A*>(b);

Now i have a pointer to one of my A base classes and i can do a->foo() .

Is this safe?

What i want to know is if i can do this double-upcasting to just have pointer to interfaces (with no data members) without the overhead of virtual inheritance. I don't plan to downcast the pointer anyway or do anything with it that isn't calling virtual methods.

I know this means having two base classes but as there are no members it shouldn't matter, or does it?

EDIT : I'm struggling to find a way to implement interfaces and i think i'll just have to use virtual inheritance.

Suppose i have a class Buffer (interface class), and a BufferImplementation class that derives from it.

Now suppose i have another interface IOBuffer (which derives from the other interface Buffer ), with a IOBufferImplementation class that must derive both from BufferImplementation and the IOBuffer interface.

In my previous example, Buffer is A, BufferImplementation is B, IOBuffer is C, and IOBufferImplementation is D.

Is this safe?

I think so. You are using one of the two paths to reach from the derived class D to Base A . You can now use the Interface Members safely.

Just one note, if there are pure virtual methods in A that is not overridden in D , then using D->B->A path will always call the overridden method in B (similar for D->C->A path), though the implementation in C was intended/useful. This will also work when A has data members, and in this particular setup, the data members inherited via D->B->A will be used.

What you have written is NOT the diamond pattern!

If you want to make this to the diamond pattern, you have to virtual inherit !

class B :  virtual public A

and

class C :  virtual public A

Your version simply derives linear from the base classes which makes D containing two times the base class A. As a result the compiler has no chance to know which A should be selected if you ask for it. If you derive with virtual, you get only one A in D.

Remember, that you must call the constructor of A in D manually. Also if the constructor of C or D calls constructor of A! This call will not happen, if you create an instance of D!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM