virtual inheritance from base struct - c++

struct A {
int i;
virtual void f() { cout << i; }
A() { i = 1; }
A(int _i) : i(_i) {}
};
struct B : A {
B() : A(2) { f(); }
void f() { cout << i+10; }
};
struct C : B, virtual A {
C() : A() {}
};
Can you please explain why in the C structure there will be two A::i and why there will be two vptr pointers to 'virtual tables methods' for C structure although A only has virtual method ?
I know when there is virtual inheritance from a common base there will be one instance of the common base not two ,Please advise!

Without virtual
When inheriting without virtual, you can imagine the memory structure to be like this:
class B : A {};
The variables of A are "inside" (just above) the variables of class B.
With virtual
When inheriting with virtual, B just has a "pointer" to A:
class B : virtual A {};
Your example
This means, your example looks like this:
class B : A
class C : B, virtual A
Only one instance of A
If you only want one instance of A, you have to use virtual two times:
class B : virtual A
class C : B, virtual A
vptr's
Here is the layout of your code as it was produced by g++ (generated with -fdump-class-hierarchy):
Class C
size=16 align=4
base size=8 base align=4
C (0xb7193440) 0
vptridx=0u vptr=((& C::_ZTV1C) + 12u)
B (0xb719f078) 0
primary-for C (0xb7193440)
A (0xb719a428) 0
primary-for B (0xb719f078)
A (0xb719a460) 8 virtual
vptridx=4u vbaseoffset=-12 vptr=((& C::_ZTV1C) + 28u)
I'm a bit rusty what concerns vpointers and vtables, so I'm not sure why there are exactly those v-pointers.
However, I can tell you, that your assumption that there is only one virtual method is wrong.
Because B inherits from A and A::f() is virtual, the derived B::f() is automatically also virtual, even if you don't explicitly write this down.
edit:
After digging a bit, I think I remember which v-pointers are needed and which are not.
However I won't give you any guarantee about the following.
In the following, the notation C.B.A means the A-subobject in B, which is in C, to distinguish the both A-subobject (C.B.A and C.A).
Each subclass needs a v-pointer. However *(C.B.A), *(C.B) and *C all point to the same location (namely the beginning of the class C which is also the beginning of C.B and C.B.A, therefore they can share one v-pointer. However a pointer to the subclass *(C.A) will point to a different location, therefore another vpointer is needed there. Also note that the subclass C.B.A won't even be accessible in your example (gcc: "warning: direct base ‘A’ inaccessible in ‘C’ due to ambiguity").
To make it a bit clearer:
If you only had the following structure
class B : A {};
class C : B {};
only one vpointer would be needed as all pointers to any subclass of C would point to the same location. The vpointer would only have to point to the vtable of either A, B or C to tell which is the run-time type of the object.

B isn't inheriting virtualy.
So you have the A struct inherited from B and another inherited virtauly.

Related

Avoid calling base constructor 2 times

Say I have several classes that inherit like so.
#include <iostream>
struct A {
A() {std::cout << "a";}
};
struct B : A {};
struct C : A {};
struct D : B, C {};
int main {
D d;
}
On executing the program, as expected, I see two A objects were constructed, one for the B and one for the C object that are constructed when creating a D object. Whoever, how can I not create two A objects? I want the same A object to be used to create B and C objects. Is this possible?
If B and C both use virtual inheritance for A, then there will only be a single base class object for each D object:
struct B : virtual A {};
struct C : virtual A {};
//...
D d; //prints "a" rather than "aa"
Live demo
If you're looking for a non-polymorphic solution, you're out of luck. Otherwise, change to the following:
struct B : virtual A {};
struct C : virtual A {};
As written, every D object has two sub-objects of type A, one inherited from class B and one inherited from class C. So the constructor of A must run twice, once for each sub-object.
If the original design is wrong, and there should only be one A sub-object, despite the use of two bases B and C, the change is to make A a virtual base of B and a virtual base of C. That way there will only be one A sub-object in a D object, and the constructor of A will only run once when a D object is constructed.

virtual inheritance and base class of base class

Consider the following code:
class A {
};
class B : public A {
};
class C : public B{
public:
C() : A() {} // ERROR, A is not a direct base of B
};
In this case GCC (4.8.1, C++99) gives me the correct error (I understand this behavior):
prog.cpp:12:8: error: type ‘a’ is not a direct base of ‘c’
However if the inheritance between b and a is virtual, this does not happen:
class A {
};
class B : virtual public A {
};
class C : public B{
public:
C() : A() {} // OK with virtual inheritance
};
Why does this work?
Is A now considered a direct base to C by the compiler?
In general, because this is how C++ tries to resolve the diamond inheritance problem http://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem (whether or it is a good or bad solution is left as an exercise to the reader).
All inheritance is a combination of an is-a and a has-a relationship...you must instantiate an instance of the parent. If you have the following classes:
class a;
class b : a;
class c : a;
class d : b,c;
Then you've instantiated an a for each b and c. d will not know which a to use.
C++ solves this by allowing virtual inheritance, which is high-overhead inheritance that allows b and c to share the same a if inherited in d (it is much more complicated than that, but you can read up on that on your own).
The most derived type in the chain needs to be able to override the instantiation of the shared class to control disparities in the way that the shared class is inherited in the parent classes. Take the following example:
class a {int x; public: a(int xx) {x=xx;} int get_x() {return x;}};
class b : public virtual a { public: b(): a(10){}};
class c : public virtual a { public: c(): a(15){}};
class d : public virtual b, public virtual c {public: d() : a (20) {}};
int main() {
d dd;
std::cout << dd.get_x() << std::endl;//20, d's constructor "wins"
return 0;
}
If d did not define what a was instantiated as, it would have definitions for conflicting instantiations (from b and c). C++ handles this by forcing the most derived class in the inheritance chain to instantiate all parent classes (the above would barf if d did NOT explicitly instantiate a, though if a supplied a default constructor that could be implicitly used) and ignoring all parent instantiations.
Why does this work?
According to the standard (10.1.4 in the FIDS), "for each distinct baseclass that is specified virtual, the most derived object shall contain a single base class subobject of that type".
Virtual base is shared between all classes that derive from it for the instance of the object. Since a constructor may only be called once for a given instaniation of an object, you have to explicitly call the constructor in the most derived class because the compiler doesn't know how many classes share the virtual base. This is because the compiler will start from the most base class's constructor and work to the most derived class. Classes that inherit from a virtual base class directly, will not, by the standard, call their virtual base classes constructor, so it must be called explicitly.
From N3337, 12.6.2
Initializing bases and members
In the definition of a constructor for a class, initializers for direct and virtual base subobjects and non-static data members can be specified by a ctor-initializer, which has the form
Perhaps someone who has better version of Standard can verify this.

Multiple inheritance

I have 2 base classes (B1 and B2) which are derived from common Base class(B), where they have a common variable (let: int x; from base B), in 1st base x=0, in the 2nd base x=10 (default values given in B1,B2 constructors).
Visually:
class B
{
int x;
protected:
B(int x) : x{x}{}
};
class B1 : public B
{
protected:
B1() : B(0){}
};
class B2 : public B
{
protected:
B2() : B(10){}
};
Now if I derive one more class:
class D : virtual public B1, virtual public B2
{
public:
D() : B1{}, B2{}{}
};
Here only one copy of x will be available as per virtual concept, now if I try to access x value with derived class object which instance of x I will get in O/p (x=0 or x=10), and why?
In order to use virtual inheritance, base B must be declared as virtual in both B1 and B2. Without that, you have non-virtual inheritance of B.
If you have non-virtual inheritance, then you have two B bases in D, so you can't access x in D without qualifying it as B1::x or B2::x
If you have virtual inheritance, then you only have one B and one x, so the two assignments to it (x=0 and x=10) will happen in whichever order you did them in, and whichever one was later will overwrite the value set by the earlier one (much as with a simple variable x with two assignments).
In your setup as you have it, B is not actually inherited virtually, because you would have to declare virtual inheritance for B in both B1 and B2 (it always has to happen at the lowest level if the two "branches" are expected to be merged higher up in the class inheritance hierarchy), i.e.
class B1 : virtual public B
{
protected:
B1() : B(0){}
};
class B2 : virtual public B
{
protected:
B2() : B(10){}
};
If you do that, initialization of B would be completely different, because there are special rules for the construction of virtual base classes:
In virtual inheritance, the virtual base class is always initialized by the most derived class. Thus, as you have implemented the constructor of D as
D() : B1(), B2(){}
and therefore don't call your B constructor explicitly, the compiler will assume that you want to call Bs default constructor. But your class B does not have a default constructor, so you would get a compiler error like this:
prog.cpp: In constructor ‘D::D()’:
prog.cpp:31:20: error: no matching function for call to ‘B::B()’
D() : B1(), B2(){}
^
Therefore, you would have to do something like
class D : public B1, public B2
{
public:
D() : B(99), B1(), B2(){}
};
and this also solves your question: The value of x will be whatever the most derived class wants it to be (99 in this case). Thus, there is no ambiguity.
PS: You also see, your question is at the heart of why it makes sense to have the special rule about virtual base class construction by the most derived class.

How does virtual inheritance actually work?

I know about the diamond problem but the thing is - when I google "virtual inheritance" the results mention only the diamond problem. I want to know how it works in general and how is it different from normal inheritance.
I know when a class (normally) inherits from another class it simply contains all its members (fields and methods, leaving aside the access levels). Some of them may be overridden or hidden by new members but they're still there. Inheritance also defines certain relationships between classes in hierarchy which affects casting and polymorphism.
Now how is virtual inheritance different? For instance:
class A
{
public:
int a;
int b;
void fun(int x)
{}
void gun(int x)
{}
};
class B : public A
{
public:
int a;
int c;
void fun(int x)
{}
void hun(int x)
{}
};
class C : virtual public A
{
public:
int a;
int c;
void fun(int x)
{}
void hun(int x)
{}
};
What are the differences between B and C? Are there any other differences that my example doesn't exploit? What does the standard say? Also, if there's a difference between C++03 and C++11 please mention it.
With a single level of inheritance, there's no difference in behaviour.
The difference is when inheriting from multiple base classes, which themselves have a common base class:
struct A {};
struct B : virtual A {};
struct C : virtual A {};
struct D : B,C {};
In this example, with virtual inheritance, D contains just one A sub-object, which its B and C subobjects share; this is the "diamond" pattern:
A
/ \
B C
\ /
D
Without virtual inheritance, it would contain two A sub-objects, and no "diamond":
A A
| |
B C
\ /
D
With or without multiple inheritance, there's still a difference if you have more than one level of inheritance: a virtual base class must be initialised by the most derived class, not by its immediate derived class. This is to avoid the ambiguity in the case of multiple inheritance, where (in the example above) both B and C would otherwise be responsible for initialising the shared A.

Acessing to a base subobject and virtual specifier c++ [duplicate]

This question already has answers here:
In C++, what is a virtual base class?
(11 answers)
Closed 8 years ago.
I'm trying to understand what exactly purpose of a virtual specifier in base class. As said in the c++14 working draft we have:
For each distinct base class that is specified virtual, the most
derived object shall contain a single base class subobject of that
type.
From this quote I'm assume that if we create an instance c of class C which is a derived class for A and B we're create an objects of A and B implicitly.
Question: How can I access to an instances of a base classes via an instance of derived class?
An object of class struct C : A, B {}; contains two base subobjects, one of type A and one of type B. You can access them "directly":
void foo(A &);
void bar(B &);
C c;
foo(c); // accesses the A-subobject
bar(c); // accesses the B-subobject
You can also say static_cast<A&>(c) and static_cast<B&>(c) explicitly, though this is not often needed. You sometimes need to disambiguate names, though:
struct A { void f(); };
struct B { void f(); };
struct C : A, B { void f(); };
C c;
c.f(); // calls the member "f" of C
c.A::f(); // calls the member "f" of the A-base subobject of c
c.B::f(); // calls the member "f" of the B-base subobject of c
All this is not really related to the concept of virtual inheritance, which says that there is only relevant base subobject, even if it is referred to through multiple distinct inheritances:
struct V {};
struct A : virtual V {};
struct B : virtual V {};
struct C : A, B {};
In this last example, an object C c has only one base subobject of type V, not two, and the V-base subobjects of the A- and B-base subobjects of c see the same V base subobject. The virtual base is "shared" across the inheritance hierarchy.
virtual specifier is not related to accessing base sub-object, rather number of base sub-object in derived object. You can access base sub-object even if the base is not virtual. virtual is here to solve other problems like diamond inheritance problem