is virtual inheritance from pure abstract classes (interfaces) necessary

Why is it that in the code below the compiler complains that PureAbstractBase is an ambiguous base class of MultiplyInheritedClass? I realize I have two copies of the PureAbstractBase in MultiplyInheritedClass and that FirstConreteClass and SecondConreteClass should be derived virtually because they're the middle row of the diamond (and that does indeed fix the problem with the code below). But even though I have two copies of the interface why is it that the code in MultiplyInheritedClass does not just override both and unambiguously pick the interface class defined in MultiplyInheritedClass?

#include <iostream> using namespace std; class PureAbstractBase { public: virtual void interface() = 0; }; // I know that changing the following line to: // class FirstConcreteClass : public virtual PureAbstractBase { // fixes the problem with this hierarchy class FirstConcreteClass : public PureAbstractBase { public: virtual void interface() { implementation(); } private: void implementation() { cout << "This is object FirstConcreteClass\n"; } }; // I know that changing the following line to: // class SecondConcreteClass : public virtual PureAbstractBase { // fixes the problem with this hierarchy class SecondConcreteClass : public PureAbstractBase { public: virtual void interface() { implementation(); } private: void implementation() { cout << "This is object SecondConcreteClass\n"; } }; class MultiplyInheritedClass : public FirstConcreteClass, public SecondConcreteClass { public: virtual void interface() { implementation(); } private: void implementation() { cout << "This is object MultiplyInheritedClass\n"; } };

Further, why do I not have issues with the following hierarchy? Doesn't the ConcreteHandler class have three copies of the AbstractTaggingInterface in this case? So why doesn't it have the same issue as the example above?

#include <iostream> using namespace std; class AbstractTaggingInterface { public: virtual void taggingInterface() = 0; }; class FirstAbstractHandler : public AbstractTaggingInterface { public: virtual void taggingInterface() { cout << "FirstAbstractHandler\n"; } virtual void handleFirst() = 0; }; class SecondAbstractHandler : public AbstractTaggingInterface { public: virtual void taggingInterface() { cout << "SecondAbstractHandler\n"; } virtual void handleSecond() = 0; }; class ThirdAbstractHandler : public AbstractTaggingInterface { public: virtual void taggingInterface() { cout << "ThridAbstractHandler\n"; } virtual void handleThird() = 0; }; class ConcreteHandler : public FirstAbstractHandler, public SecondAbstractHandler, public ThirdAbstractHandler { public: virtual void taggingInterface() = { cout << "ConcreteHandler\n"; } virtual void handleFirst() {} virtual void handleSecond() {} virtual void handleThird() {} };

I am trying to wrap my head around all of this because I had a conversation with a colleague recently where he claimed that if you were inheriting from pure virtual classes (interfaces) without any data members then virtual inheritance was not necessary. I think understanding why the former code example does not work and the latter does would go a long way to getting this straight in my head (and clear up what exactly he meant by his comment). Thanks in advance.

-------------Problems Reply------------

You need virtual inheritance to overcome the diamond-ambiguity:

class FirstConcreteClass : public virtual PureAbstractBase { ... };
class SecondConcreteClass : public virtual PureAbstractBase { ... };


Long-winded explanation: Suppose you have this:

// *** Example with errrors! *** //
struct A { virtual int foo(); };
struct B1 : public A { virtual int foo(); };
struct B2 : public A { virtual int foo(); };
struct C: public B1, public B2 { /* ... */ }; // ambiguous base class A!

int main() {
A * px = new C; // error, ambiguous base!
px->foo(); // error, ambiguous override!
}

The inheritance of the virtual function foo is ambiguous because it comes in three ways: from B1, from B2 and from A. The inheritance diagram forms a "diamond":

/-> B1 >-\
A-> ->C
\-> B2 >-/

By making the inheritance virtual, struct B1 : public virtual A; etc., you allow any baseclass of C* to call the correct member:

struct A { virtual int foo(); };
struct B1 : public virtual A { virtual int foo(); };
struct B2 : public virtual A { virtual int foo(); };
struct C: public B1, public B2 { virtual int foo(); };

We must also define C::foo() for this to make sense, as otherwise C would not have a well-defined member foo.

Some more details: Suppose we now have a properly virtually-inheriting class C as above. We can access all the various virtual members as desired:

int main() {
A * pa = new C;
pa->foo(); // the most derived one
pa->A::foo(); // the original A's foo

B1 * pb1 = new C;
pb1->foo(); // the most derived one
pb1->A::foo(); // A's foo
pb1->B1::foo(); // B1's foo

C * pc = new C;
pc->foo(); // the most derived one
pc->A::foo(); // A's foo
pc->B1::foo(); // B1's foo
pc->B2::foo(); // B2's foo
pc->C::foo(); // C's foo, same as "pc->foo()"
}

Update: As David says in the comment, the important point here is that the intermediate classes B1 and B2 inherit virtually so that further classes (in this case C) can inherit from them while simultaneously keeping the inheritance from A unambiguous. Sorry for the initial mistake and thanks for the correction!

Your first example fails because the compiler cannot disambiguate between the three implementations of implementation(). You are overriding that method in MultiplyInheritedClass, which actually overrides both FirstConcreteClass::implementation and SecondConcreteClass::implementation (once virtual, always virtual). However, both virtual calls still exist in the interface of MultiplyInheritedClass, which makes the call ambiguous at the call site.

The reason that your example works without virtual inheritance is that there is no conflicting implementation of the common base class. Put another way:

class Base
{
public:
void DoSomething() {
std::cout << "TADA!";
}
}

class One : public Base
{
//...
}

class Two : public Base
{
//...
}

class Mixed : public One, public Two
{
//...
}

int main()
{
Mixed abc;
abc.DoSomething(); //Fails because the compiler doesn't know whether to call
// One::DoSomething or Two::DoSomething, because they both
// have implementations.

//In response to comment:
abc.One::DoSomething(); //Succeeds! You removed the ambiguity.
}

Because your example has all pure virtual functions, there's no multiple implementations which the compiler needs to disambiguate. Therefore, only one implementation exists, and the call is unambiguous.

I tried both of the question codes and they worked fine when instantiating an object of the multi-inherited class. It didn't work only with polymorphism, like this for example:

PureAbstractBase* F;
F = new MultiplyInheritedClass();

And the reason is clear: it doesn't know to which copy of the Abstract base class it should be linked (sorry for bad expressions, I understand the idea but can't express it). And since inherting virtaully makes only one copy exist in the derived class, then it's fine.

Also the code of Billy ONeal is not clear at all, what should we place instead of the comments?

If we place:

public:
void DoSomething()
{ std::cout << "TADA!"; }

it works fine, because of no virtuality.

I work on Visual Studio 2008.

Why not do it like this (suggested in Benjamin Supnik's blog entry):

#include <iostream>

class PureAbstractBase {
public:
virtual void interface() = 0;
};

class FirstConcreteClass : public PureAbstractBase {
public:
virtual void interface() { implementation(); }
private:
void implementation() { std::cout << "Fisrt" << std::endl; }
};

class SecondConcreteClass : public PureAbstractBase {
public:
virtual void interface() { implementation(); }
private:
void implementation() { std::cout << "Second" << std::endl; }
};

class MultiplyInheritedClass : public FirstConcreteClass,
public SecondConcreteClass
{
public:
virtual void interface() { implementation(); }
private:
void implementation() { std::cout << "Multiple" << std::endl; }
};

int main() {
MultiplyInheritedClass mic;
mic.interface();

FirstConcreteClass *fc = &mic; //disambiguate to FirstConcreteClass
PureAbstractBase *pab1 = fc;
pab1->interface();

SecondConcreteClass *sc = &mic; //disambiguate to SecondConcreteClass
PureAbstractBase *pab2 = sc;
pab2->interface();
}

which gives:

Multiple
Multiple
Multiple

This way:

  • no virtual bases are involved (do you really need them?)
  • you can call the overriden function via a an instance of the MultiplyInheritedClass
  • ambiguity is removed by a two-stage conversion
Category:c# Views:0 Time:2011-06-19

Related post

  • virtual desctructor on pure abstract base class 2010-07-26

    I have struct IMyInterface { virtual method1() = 0; virtual method2() = 0; }; GCC insists that I have struct IMyInterface { virtual method1() = 0; virtual method2() = 0; virtual ~IMyInterface(){}; }; I dont see why. A pure interface is all about the

  • pure abstract class and interface 2010-01-19

    This question already has an answer here: When to use an interface instead of an abstract class and vice versa? 18 answers Can anyone tell me what exactly the difference between an completely abstract class and an interface? An Abstract class can als

  • Is it a good convention to virtually inherit from pure virtual (interface) classes? 2012-03-03

    I often use pure virtual classes (interfaces) to reduce dependencies between implementations of different classes in my current project. It is not unusual for me to even have hierarchies in which I have pure virtual and non-pure virtual classes that

  • typedef inheritance from a pure abstract base 2010-09-03

    Edit: Found duplicate I've whittled down some problem code to the simplest working case to illustrate the following: my typedef in a pure abstract base class is not being inherited by the derived class. In the code below I'd like to inherit the syste

  • C++, virtual inheritance, strange abstract class + clone problem 2011-08-03

    Sorry for the larger amount of the source code. There three abstract classes P, L, PL. The third class PL is derived from classes P and L using the virtual inheritance: template <typename T> //Abstract class class P { public: virtual ~P() = 0;

  • JVM Implementation difference between interface and pure abstract class? 2012-02-21

    Me and my friends wondered if there really is a difference inside the JVM between interfaces and pure abstract classes, or if it is just really syntactic sugar. I don't really see why there would be difference, but it might not be so far-fetched. ---

  • Parametrized constructor in virtually inheriting abstract class 2011-10-09

    I have a classical virtual inheritance diamond: class A { protected: A(const char *x) { ... } } class B: public virtual A { protected: B(): A(NULL) { ... } public: virtual void foo() = 0; } class C: public virtual A { protected: C(): A(NULL) { ... }

  • C++ Multiple Virtual Inheritance vs. COM 2008-11-18

    The net is overflowing with explanations of the "dreaded diamond problem". So is StackOverflow. I think I understand that bit, but I fail to translate that knowledge into comprehending something similar yet different. My question begins as a pure C++

  • Is it correct that header files in C++ and abstract class/interface implementations in Java are both the same idea? 2011-08-17

    I am a little with familiar with C++ and I know that for almost every header file, I must create source file to go with it. Now I am looking into java interfaces and implementation and it looks as the same thing. At first you just name the variables

  • Can a class still be pure abstract if it has a non-pure destructor? 2011-09-28

    I am working on an exercise which asks me to take a base class Rodent and make it a pure abstract class. My understanding of a pure abstract class is that it acts as an interface and only contains pure virtual functions. Although this is an easy exer

  • What's the simplest way to satisfy a pure abstract method with methods from other base classes 2011-11-12

    Edit: Per some comments, by simple I mean a) less code, b) easy to maintain, and c) hard to get wrong. Edit #2: Also, using containment instead of private inheritance is not objectionable if it does indeed simplify the implementation of InterfaceImpl

  • Data isolation between pure abstract class against its implmentation and the true meaning of pure abstract class? 2011-12-29

    In Bjarne Stroustrup's book "The C++ Programming Language", it is stated that a derived class from a super class in a class hierarchy, in many case, gets access to the data of the super class. The book suggests this is a problem, because the sharing

  • Virtual inheritance and delegated implementation 2012-03-18

    I am developing an api for internal and external usage. On Visual Studio 10. I have a virtual base class IA and a derived virtual base class IB. I implement IA with class A and then derive a concrete implementation for IB off of B. This to my underst

  • virtual destructor vs pure virtual destructor 2009-08-02

    I understand the need for a virtual destructor. But why do we need a pure virtual destructor? In one of the C++ articles, the author has mentioned that we use pure virtual destructor when we want to make a class abstract. But we can make a class abst

  • Why should I declare a virtual destructor for an abstract class in C++? 2008-11-07

    I know it is a good practice to declare virtual destructors for base classes in C++, but is it always important to declare virtual destructors even for abstract classes that function as interfaces? Please provide some reasons and examples why. ------

  • abstract an Interface `ISingleton` to be base class 2009-09-24

    I have 3 interface classes IVideo , IAudio , IGPIO and three other classes that will implement those interface: Video_impl , Audio_impl , GPIO_impl. Things is simple so far. But then ,I want all those object to be singleton. Here are the questions: I

  • C++ vtable resolving with virtual inheritance 2010-06-18

    I was curious about C++ and virtual inheritance - in particular, the way that vtable conflicts are resolved between bass and child classes. I won't pretend to understand the specifics on how they work, but what I've gleamed so far is that their is a

  • why virtual is allowed while implementing the interface methods? 2010-12-17

    I have one specific query with the interfaces. By default interface methods are abstract and virtual so if we implement that interface and gives definition in the class we actually override that method but when we mark the method as a virtual again i

  • When virtual inheritance IS a good design? 2011-01-05

    EDIT3: Please be sure to clearly understand what I am asking before answering (there are EDIT2 and lots of comments around). There are (or were) many answers which clearly show misunderstanding of the question (I know that's also my fault, sorry for

Copyright (C) dskims.com, All Rights Reserved.

processed in 0.139 (s). 11 q(s)