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

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

Related

What is a base class subobject?

I got that subobjects are member subobjects, base class subobjects and arrays.
I couldn't find anything that explicit explain the two first terms. In the following code for example:
struct A{int a;};
struct B{int b;};
struct C:public A,public B{};
I think that: int a is a member subobject of a possible, not yet instantiated, object of type A; int a is a base class subobject of a possible, not yet instantiated, object of type C. Is it Right? What is the definition of member subobject and base class subobject? Could you provide examples?
Whenever a class inherits from another one it inherits, too, an instance of that class:
class A { };
class B : A { };
Then class B internally looks like:
class B
{
A a; // <- implicit base class sub-object, not visible to you
};
Note that in some cases there might be even be more than one A!
class A { };
class B : A { };
class C : A { };
class D : C, B { };
D then internally looks like:
class D
{
B b; // { A a; }
C c; // { A a; }
};
with b and c being the base class sub-objects; or in a flattened representation:
class D
{
A aFromB; // inherited from B, but not a sub-object of D itself
// other members of B
A aFromC; // inherited from C, again not a sub-object of D
// other members of C
};
B and C base class sub-objects are not visible in this representation, still they are there in form of the respective A instance combined with the respective other members (think of having braces around).
If you want to avoid duplicates of A, you need to inherit virtually: class B : virtual A { } – all virtually inherited (directly or indirectly) instances of A are then combined into one single instance (though if there are non-virtually inherited ones these remain in parallel to the combined one), consider:
class A { };
class B : A { };
class C : virtual A { };
class D : virtual A { };
class E : A, B, C
{
A combinedAFromCAndD;
// other members of B
// other members of C
A separateAFromD
// other members of D
};
Note: These layouts above are just examples, concrete layouts might vary.
In your code, the base class subobjects of instances of C are the instances of A and B contained inside it. Each of those subobjects has a subobject itself (a and b); those are not considered subobjects of the instance of C (because they're subobjects of subobjects), but are considered "nested objects" of the instance of C.

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.

Default constructor getting called while using virtual inheritance [duplicate]

This question already has an answer here:
Why is Default constructor called in virtual inheritance?
(1 answer)
Closed 9 years ago.
In the following code when I create the object of C then A'a default constructor is getting called through B's constructor, why is that happening?
#include <iostream>
using namespace std;
class A
{
public:
int a;
A(int z): a(z) {cout<<"a is "<<a;}
A() { cout<<" it came here\n";}
};
class B: public virtual A
{
public:
B(int z): A(z) {cout<<"in B and z is "<<z<<"\n"; }
};
class C:public B
{
public:
C(int z): B(z) {cout<<" In C\n"; }
};
int main()
{
C b(6);
cout<<b.a;
return 0;
}
That's how virtual inheritance is described in the standard.
[12.6.2] — First, and only for the constructor of the most derived class (1.8), virtual base classes are initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where “left-to-right” is the order of appearance of the base classes in the derived class base-specifier-list.
In particular, when constructing C, the A subobject is initialized before anything else (including the B subobject). Since A is not in the mem-initializers list of the offending C constructor, the default constructor of A is used for that.
[12.6.2] — Then, direct base classes are initialized in declaration order as they appear in the base-specifier-list (regardless of the order of the mem-initializers).
Then the B subobject is constructed.
[12.6.2] A mem-initializer where the mem-initializer-id denotes a virtual base class is ignored during execution of a constructor of any class that is not the most derived class.
: A(z) in the constructor of B is ignored when constructing the B subobject of C.
In the everyday language this means you have to initialize a virtual base class in each direct or indirect derived class, as if it were a direct derived class. If you forget to do so, a default constructor will be forced, with potentially devastating consequences. (That's why you should strive to have either only the default constructor or no default constructor at all in any virtual base class).

How is this initialization list implemented using a virtual class?

#include<iostream.h>
class A{
public:
int i;
A(int j=3):i(j){}
};
class B:virtual public A{
public:
B(int j=2):A(j){}
};
class C:virtual public A{
public:
C(int j=1):A(j){}
};
class D:public B, public C {
public:
D(int j=0):A(j), B(j+1), C(j+2){}
};
int main()
{
D d;
cout<<d.i;
return 0;
}
I am not being able to understand how the final output is zero. Every time j is initialized in default way to some fixed value, how is the value initialized in the constructor of class D being passed to class A?
Since A is a virtual base class, it should be constructed only once, so it is not possible to create it with different constructor parameters, and the C++ compiler has to choose one way of creating a base class.
The obvious question is: which one is used?
And the rule is: the one specified in the most derived class that inherits A directly.
The initialization order is simple: first A (with the parameter value from D constructor initialization list), then B (it is D's first ancestor; and it uses the instance of A created before), then C (and it shares the same A instance), finally D (and it also shares the same A object as B and C).
The rule with virtual base inheritance is:
"The most derived class in a hierarchy must construct a virtual base"
In your case, from the most derived class D You explicitly called the constructor of A by passing an argument 0 So it sets the i to 0. As mentioned in rule virtual base class is constructed through most derived class only and the other constructor calls through intermediate hierarchy have no effect since it is only constructed once.
The order of calling is:
A(int)
B(int)
C(int)
Good Read:
Why virtual base class constructors called first?