Given two classes with a common virtual base class:
class Base {};
class Derived1 : public virtual Base {};
class Derived2 : public virtual Base {};
Is there any difference between these two further derived classes?:
class Derived3 : public virtual Base, public Derived1, public Derived2 {};
class Derived3 : public Derived1, public Derived2 {};
The first also derives directly from the virtual base class, but I think that has no effect, because it's shared with Derived1 and Derived2.
They say the same thing. The only difference is that if you removed public Derived1 and public Derived2 from both definitions of Derived3, the first one would still inherit from Base and the second one would not.
EDIT: I haven't thought carefully about whether there is some weird cross-cast situation where the two would also behave differently, although I don't think there is.
There is no difference between those examples.
But in a more complicated scenario, directly inheriting an otherwise inherited virtual base might change the order of construction / destruction of the base class subobjects.
I do not think there is any difference in object layout because the intention of virtual inheritance is to avoid having two copies of Base (or three copies in case 1).
So all the difference is in your intentions and really readability of the code.
Related
Regarding the size of the derived class, is it better to have a "chain" of inheritance or inherit everything in the lowest derived class?
for example, what is better between:
class Base {
virtual void something() = 0;
};
class Derived1 {
// ...
};
class Derived2 : public Derived1, public Base {
// ...
};
and
class Base {
virtual void something() = 0;
};
class Derived1 : public Base {
// ...
};
class Derived2 : public Derived1 {
// ...
};
In the second case, will it have to store two vtable pointers and just one in the first case?
In the first case, I have a sizeof(Derived) lower that in the second case.
What you're seeing as far as i can see is simply an empty base class optimization.
See the godbolt I've prepared. When you don't have empty classes, the sizes are identical.
https://godbolt.org/z/HhiJz6
To specifically address your question Regarding the size of the derived class, is it better to have a "chain" of inheritance or inherit everything in the lowest derived class?
I guess if you have an empty base class in there, you could claim it to be "better" in terms of size of the class, but that is pretty dependent on the specifics of the way the class is defined that could change at any time.
I wouldn't base an inheritance structure on it unless i was really pressed for space.
Let's say I have an interface that inherits from another interface (pure abstract class)
class BaseInterface
{};
Then another interface builds upon BaseInterface
class ExtendedInterface : public BaseInterface
{};
Now, I have a concrete class that implements BaseInterface:
class Base : public BaseInterface
{};
Now, I want to implement ExtendedInterface, but since I already have Base I want to fill out the BaseInterface members with base. E.g.:
class Extended : public ExtendedInterface, public Base
{};
This doesn't seem to work. I get complaints that I cannot instantiate extended since it is an abstract class. The only way I can get it to work is by using virtual inheritance, but then I get compiler warnings about inheriting via dominance.
What's the problem ?
With your multiple inheritance, Extended inherits two times from BaseInterface. This means that there are two independent BaseInterface subobjects:
one is inherited via the concrete Base class, which has overridden all the pure virtual functions.
but the other is inherited via ExtendedInterface class, which is still abstract.
In consequence, as some subobjects of Extended still have pure virtual functions, your class is still an abstract class that can't be instantiated.
How to solve it ?
As despite the multiple inheritance you apparently expect to have only one BaseInterface, you need to use virtual inheritance:
class BaseInterface
{ virtual void test()=0; }; // abstract class
class ExtendedInterface : public virtual BaseInterface // virtual inheritance
{}; // abstract class
class Base : public virtual BaseInterface // virtual inheritance
{ void test() override {} }; // concrete class
class Extended : public ExtendedInterface, public Base // multiple
{}; // thanks to virtual inheritance, concerete class
With this logic, there will be only one BaseInterface in Extended, with virtual functions overridden, and you can instantiate it.
Here an online demo
Consider the following sample codes which shows multilevel inheritance:
Case1 : Here the class derived1 is derived from the class base through virtual inheritance and the class derived2 is derived from the class derived1 directly.
class base
{
};
class derived1 : virtual public base
{
};
class derived2 : public derived1
{
};
Case2 : Same as Case1 except that no virtual inheritance is involved
class base
{
};
class derived1 : public base // no virtual inheritance
{
};
class derived2 : public derived1
{
};
Suppose i create an object of the class derived2 in both cases.
How does Case1 and Case2 differ with respect to the containment of sub-objects with in the object of derived2?
Does Case1 have significance over Case2 ?
PS: I am clear with the importance of a virtual base class during multiple inheritance.
Without multiple instances of a base class in an inheritance hierarchy there are (at least) two other issue to consider with virtual base classes.
First, a virtual base class is always initialized by the most derived class under construction and before non-virtual base classes. This is most obvious when intermediate classes pass parameters to the virtual base class constructor in their member initialization lists. These initializers will be ignored. It can also make a difference to the order of construction of base classes.
Second, it is not possible to perform a static_cast from a virtual base class to a class that inherits from it.
There is additional information stored when using virtual inheritance. This is to allow dynamic casts to properly resolve to derived classes in the case of a diamond situation. Your code does not have a diamond situation, so the information is not used.
The additional information can be made visible if you add a data member to the base class:
class base {
protected:
int i;
};
If you now print the size of each of the derived classes in each of your two cases, you will observe a difference in their sizes from one case to the other.
Edit: Charles Bailey makes excellent points about semantic differences with using virtual inheritance. His first point is particularly interesting, and should be given more consideration. His point is basically that derived2 has an implicit diamond topology. That is, assuming derived1 virtually inherits from base:
class base {};
class derived1 : virtual public base {};
Then, there is no difference between these three versions of derived2, they all behave like the first one:
class derived2 : virtual public base, public derived1 {};
class derived2 : public derived1, virtual public base {};
class derived2 : public derived1 {}
This implies that there is an implicit diamond created when you derive from a class like derived1 (that is, one that has used virtual inheritance).
base
| \
| \.(virtual)
| / \
| /___\
| |
| derived1
| /
| /
|./
/ \
/___\
|
derived2
To further illustrate the point, this is allowed when derived1 uses virtual inheritance:
class derived2 : public derived1 {
public:
derived2 () : base() {}
};
But, it is not allowed if derived1 does not use virtual inheritance.
Virtual inheritence has no significance in your case.
It is only indented for diamon inheritence like:
B: A
C: A
D: B, C
In this case inheritence from A in both cases should be virtual.
Virtual inheritance becomes significant only when the class is included as a base class more than once. In fact the specifier virtual means here "include only once".
When you do not have multiple inheritance you cannot specify the same class several times (circular inheritance is a clear syntax error). Then it comes to how good smart is the optimization in your compiler. If the compiler is perfect, then there is no difference. Practically speaking you pick up the risk that compiler will add something that has relation to multiple inheritance to your class. The less often some feature of the language is used, the bigger the risk that compiler will get confused. Compiler is typically a high quality program, but still this is only a program.
If I have something like
class Base1 {};
class Base2 {};
class Derived : public Base1, public Base2 {};
Then order of constructor call on making object of Derived is
Base1
Base2
i.e in the order they appear in
class Derived : public Base1, public Base2 {};
But If I change it to
class Derived : public Base1, virtual public Base2 {};
Then Order of constructor call becomes
Base2
Base1
I am not able to understand why this is so ?
Another simple doubt:
what can be the meaning and purpose of inheriting Base1 virtually.
Those are just the rules. The most derived class being constructed initializes all the virtual base classes in the hierarchy first before starting the initialization of its non-virtual direct bases.
The rules come from the standard (ISO/IEC 14882:2011), section 12.6.2 [class.base.init] / 10.
A rationale for this approach would be that it ensures that all base classes are initialized before their derived classes whether or not they are virtual bases.
On the order of initialization, Charles has already answered properly: those are the rules, first the virtual bases in the order of declaration, then the non-virtual bases in the order of declaration, then member variables in the order of declaration.
What is the meaning of virtual inheritance? It means that your object derives from that particular base, but that if in a hierarchy more than one subobjects (bases of the complete type) inherit virtually from the same base type, only one base subobject will be present. You can read the virtual keyword there as I am willing to share my base with other objects in the complete type.
struct ubase {};
struct sbase {};
struct A : ubase, virtual sbase {}; // has a sbase subobject, but is willing to share..
struct B : ubase, virtual sbase {}; // ... but want to have my own ubase
struct C : A, B {}; // only one sbase subobject, shared by A and B
// ... but two ubase subobjects, A::ubase and B::ubase
As per the second question, when do you want to use virtual inheritance? Whenever in a type hierarchy you might end up inheriting from the same base more than once and in your design all those occurrences of the base class are just one. In general, it is quite uncommon to use virtual inheritance other than in a few particular cases.
As for inheriting virtually. It comes into play when you have a derived class like below
class A {};
class B : public virtual A {} ;
class C : public virtual A {} ;
class D : B, C { } // this class has only one instance of A!
aka the diamond problem!
The scenario generating this is quite complex so I'll strip out a few pieces and give an accurate representation of the classes involved.
/* This is inherited using SI by many classes, as normal */
class IBase
{
virtual string toString()=0;
};
/* Base2 can't inherit IBase due to other methods on IBase which aren't appropriate */
class Base2
{
string toString()
{
...
}
};
/* a special class, is this valid? */
class Class1 : public IBase, public Base2
{
};
So, is this valid? Will there be conflicts on the toString? Or can Class1 use Base2::toString to satisfy IBase?
Like I say there are lots of other things not shown, so suggestions for major design changes on this example are probably not that helpful... though any general suggestions/advice are welcome.
My other thought was something like this:
class Class1 : public IBase, public Base2
{
virtual string toString()
{
return Base2::toString();
}
};
This builds and links, but I've no idea if it has hidden bugs.
You can fix this using "virtual inheritance".
Consider creating a common base class that only defines a pure virtual toString method (or, in reality, pure virtual version of whatever methods it makes sense for both IBase and Base2 to have), e.g.
class Stringable {
public:
virtual string toString() = 0;
};
Then, have both IBase and Base2 inherit from this Stringable class:
class IBase : public Stringable
{
};
class Base2 : public Stringable
{
public:
virtual string toString()
{ ... }
};
Now this as it is still won't work because Class1 will have inherited two copies of the Stringable base class, only one of which has an implementation for toString in its inheritance hierarchy. This is known as the "dreaded diamond". However, if IBase and Base2 were to inherit virtually from Stringable, like this:
class IBase : virtual public Stringable
{
};
class Base2 : virtual public Stringable
{
public:
virtual string toString()
{ ... }
};
Then this tells the compiler that there should only be one common Stringable base class even if IBase and Base2 are both inherited by one class, which is exactly what you want, because then the Base2::toString is used for Class1.
Your second idea has no "hidden bugs", but is somewhat of a pain in the butt to implement repeatedly, as you probably realize.
This should work just fine.
You're properly overriding the IBase interface to provide a definition of ToString() that will be forwared up to Base2::ToString().
Note that Base2 doesn't declare toString() as virtual, so Class1 can't override the behavior of Base2::ToString. No ambiguity there.
And, in addition, this is not the classic diamond problem in multiple inheritance solved by virtual inheritance because they don't share a base class.