tags:

views:

2683

answers:

12

I think you might dislike C++ crappy features but I just want to know what is virtual base class and what it means:

Let me show an example:

class Foo
{
public:
    void DoSomething() { /* ... */ }
};

class Bar : public virtual Foo
{
public:
    void DoSpecific() { /* ... */ }
};

Please teach me!

A: 

@Paul:

VC++ compiler compiles my codes very well without any error and warning messages. I can create Bar and also Foo.

@Paul:

Can you check this code? VC++ has no problem compile this codes.

#include "stdafx.h"
#include <iostream>
using namespace std;

class Foo
{
public:
    void DoSomething() { cout << "Do Something" << endl; }
};

class Bar : public virtual Foo
{
public:
    void DoSpecific()
    {
        cout << "Do Specific" << endl;
    }
};

int _tmain(int argc, _TCHAR *argv[])
{
    Foo f;
    f.DoSomething();

    Bar b;
    b.DoSomething();
    b.DoSpecific();
    return 0;
}
popopome
A: 

You cannot create object of Foo with the =0...

poulejapon
A: 

It means a call to a virtual function will be forwarded to the "right" class.

C++ FAQ Lite FTW.

In short, it is often used in multiple-inheritance scenarios, where a "diamond" hierarchy is formed. Virtual inheritance will then break the ambiguity created in the bottom class, when you call function in that class and the function needs to be resolved to either class D1 or D2 above that bottom class. See the FAQ item for a diagram and details.

It is also used in sister delegation, a powerful feature (though not for the faint of heart). See this FAQ.

Also see Item 40 in Effective C++ 3rd edition (43 in 2nd edition).

wilhelmtell
+26  A: 

Virtual base classes, used in virtual inheritance, is a way of preventing multiple "instances" of a given class appearing in an inheritance hierarchy when using multiple inheritance.

Consider the following scenario:

class A { public: void Foo() {} }
class B : public A {}
class C : public A {}
class D : public B, public C {}

The above class hierarchy results in the "dreaded diamond" which looks like this:

  A
 / \
B   C
 \ /
  D

An instance of D will be made up of B, which includes A, and C which also includes A. So you have two "instances" (for want of a better expression) of A.

When you have this scenario, you have the possibility of ambiguity. What happens when you do this:

D d;
d.Foo(); // is this B's Foo() or C's Foo() ??

Virtual inheritance is there to solve this problem. When you specify virtual when inheriting your classes, you're telling the compiler that you only want a single instance.

class A { public: void Foo() {} }
class B : public virtual A {}
class C : public virtual A {}
class D : public B, public C {}

This means that there is only one "instance" of A included in the hierarchy. Hence

D d;
d.Foo(); // no longer ambiguous

Hope that helps as a mini summary. For more information, have a read of this and this.

Cheers!


@Paul: No worries ;) Editing my comment.

OJ
A: 

@OJ My wrong... I delete my answer

@popopome "virtual void DoSomething() = 0"

poulejapon
+2  A: 

A virtual base class is a class that cannot be instantiated : you cannot create direct object out of it.

I think you are confusing two very different things. Virtual inheritance is not the same thing as an abstract class. Virtual inheritance modifies the behaviour of function calls; sometimes it resolves function calls that otherwise would be ambiguous, sometimes it defers function call handling to a class other than that one would expect in a non-virtual inheritance.

wilhelmtell
A: 

You're being a little confusing. I dont' know if you're mixing up some concepts.

You don't have a virtual base class in your OP. You just have a base class.

You did virtual inheritance. This is usually used in multiple inheritance so that multiple derived classes use the members of the base class without reproducing them.

A base class with a pure virtual function is not be instantiated. this requires the syntax that Paul gets at. It is typically used so that derived classes must define those functions.

I don't want to explain any more about this because I don't totally get what you're asking.

Baltimark
A "base class" that is used in a virtual inheritance becomes a "virtual base class" (in the context of that precise inheritance).
Luc Hermitte
+1  A: 

Virtual classes are not the same as virtual inheritance. Virtual classes you cannot instantiate, virtual inheritance is something else entirely.

Wikipedia describes it better than I can. http://en.wikipedia.org/wiki/Virtual_inheritance

bradtgmurray
There is no such thing as "virtual classes" in C++.There are however "virtual base classes" which are "virtual" regarding a given inheritance.What you refer is what is officially called "abstract classes".
Luc Hermitte
+2  A: 

I'd like to add to OJ's kind clarifications.

Virtual inheritance doesn't come without a price. Like with all things virtual, you get a performance hit. There is a way around this performance hit, that is questionably less elegant.

Instead of breaking the diamond by deriving virtually, you can add another layer to the diamond, to get something like this:

   B
  / \
D11 D12
 |   |
D21 D22
 \   /
  DD

Non of the class inherit virtuall, all inherit publicaly. Classes D21 and D22 will then hide virtual function f() which is ambiguous for DD, perhaps by declaring the function private. They'd each define a wrapper function, f1() and f2() respectively, each calling class-local (private) f(), thus resolving conflicts. Class DD calls f1() if it wants D11::f() and f2() if it wants D12::f(). If you define the wrappers inline you'll probably get about zero overhead.

Of course, if you can change D11 and D12 then you can do the same trick inside these classes, but often that is not the case.

wilhelmtell
+11  A: 

About the memory layout

As a side note, the problem with the Dreaded Diamond is that the base class is present multiple times. So with regular inheritance, you believe you have:

  A
 / \
B   C
 \ /
  D

But in the memory layout, you have:

A   A
|   |
B   C
 \ /
  D

This explain why when call A::foo(), you have an ambiguity problem. But the real problem comes when you want to use a member variable of A. For example, let's say we have:

class A
{
    public :
       foo() ;
       int m_iValue ;
} ;

When you'll try to access m_iValue from D, the compiler will protest, because in the hierarchy, it'll see two m_iValue, not one. And if you modify one, say, B::m_iValue (that is the A::m_iValue parent of B), C::m_iValue won't be modified (that is the A::m_iValue parent of C).

This is where virtual inheritance comes handy, as with it, you'll get back to a true diamond layout, with not only one foo() method only, but also one and only one m_iValue.

What could go wrong?

Imagine:

  • A has some basic feature.
  • B adds to it some kind of cool array of data (for example)
  • C adds to it some cool feature like an observer pattern (for example, on m_iValue).
  • D inherits from B and C, and thus from A.

With normal inheritance, modifying m_iValue from D is ambiguous and this must be resolved. Even if it is, there are two m_iValues inside D, so you'd better remember that and update the two at the same time.

With virtual inheritance, modifying m_iValue from D is ok... But... Let's say that you have D. Through its B interface, you attached an observer. And through its C interface, you update the cool array, with has the side effect of directly changing m_iValue...

As the change of m_iValue is done directly (without using a virtual accessor method), the observer "listening" through B won't be called, because the code implementing the listening is in B, and C doesn't know about it...

Conclusion

If you're having a diamond in your hierarchy, it means that you have 95% to have done something wrong with said hierarchy.

paercebal
Your 'what could go wrong' is due to direct access to a base member, not due to multiple inheritance. Get rid of 'B" and you have the same problem. Basic rule of: 'if its not private, it should be virtual' avoids the problem. m_iValue is not virtual and therefor should be private
Chris Dodd
@Chris Dodd: Not exactly. What happens with m_iValue would have happened to any symbol (*e.g. typedef, member variable, member function, cast to the base class, etc.*). This really is a multiple inheritance issue, an issue that users should be aware to use multiple inheritance correctly, instead of going the Java way and conclude "Multiple inheritance is 100% evil, let's do that with interfaces".
paercebal
+1  A: 

In addition to what has already been said about multiple and virtual inheritance(s), there is a very interesting article on Dr Dobb's Journal: Multiple Inheritance Considered Useful

Luc Hermitte
A: 

Explaining multiple-inheritance with virtual bases requires a knowledge of the C++ object model. And explaining the topic clearly is best done in an article and not in a comment box.

The best, readable explanation I found that solved all my doubts on this subject was this article: http://www.phpcompiler.org/articles/virtualinheritance.html

You really won't need to read anything else on the topic (unless you are a compiler writer) after reading that...

lenkite