In C++, what is a virtual base class?
I want to know what a "virtual base class" is and what it means.
Let me show an example:
class Foo
{
public:
void DoSomething() { /* ... */ }
};
class Bar : public virtual Foo
{
public:
void DoSpecific() { /* ... */ }
};
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. A good example is also available here.
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 D::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 C
interface, you attached an observer. And through its B
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 C
won't be called, because the code implementing the listening is in C
, and B
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.
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...
链接地址: http://www.djcxy.com/p/78936.html上一篇: 虚拟基类子对象的多个实例(真的)
下一篇: 在C ++中,什么是虚拟基类?