0

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.

Banex
  • 2,890
  • 3
  • 28
  • 38
  • This isn't a diamond, since there's no virtual inheritance. Hence the ambiguity. – Mike Seymour May 10 '14 at 11:47
  • As @MikeSeymour already says this isn't diamond pattern. There is no problem other than (1) the ambiguity and (2) that comparing interface pointers does not reliably establish *object identity* (you can have at least two different interface pointers to same object). – Cheers and hth. - Alf May 10 '14 at 11:58
  • in addition to the previous 2 posts, could it be that you have a design problem? Multiple inheritance is rarely a good idea. – Richard Hodges May 10 '14 at 12:19
  • @RichardHodges It could be a flaw in my design, however i'm struggling in finding a good way to implement interfaces. I'll edit my question. – Banex May 10 '14 at 12:24
  • If you have an issue with the diamond pattern (--independently whether it is really such one), why don't routinely use virtual inheritance? `class B : public virtual A`, and the same for `C`. There aren't that many disadvantages, see [here](http://stackoverflow.com/questions/4543537/in-c-should-i-almost-always-use-virtual-inheritance). – davidhigh May 10 '14 at 12:35
  • @davidhight It's a performance-critical application. I did some tests and there's a slight slowdown when using virtual inheritance (due to pointer indirection). However i'll use it if that's the only choice. – Banex May 10 '14 at 12:39
  • If it is performance-critical, I would consider rewriting it in generic-programming style, e.g. by using CRTP. – davidhigh May 10 '14 at 12:49

2 Answers2

1
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.

Rakib
  • 7,435
  • 7
  • 29
  • 45
0

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!

Klaus
  • 24,205
  • 7
  • 58
  • 113
  • What he has written IS the diamond "pattern", although it's not a design pattern but a "oh crap how did I end up here?" sort of anti-pattern. What you're describing is a *solution* to the problems presented of the diamond pattern - a solution only ever to be used if you absolutely *positively* can't refactor the diamond out! – Grimm The Opiner Jul 01 '15 at 14:57