Constructors calling in c++ (inherited classes) - c++

#include <iostream>
class A
{
public:
A() { std::cout << "A's constructor called\n"; }
};
class B
{
public:
B() { std::cout << "B's constructor called\n"; }
};
class C: public B, public A // Note the order
{
public:
C() { std::cout << "C's constructor called\n"; }
};
int main()
{
C c;
return 0;
}
Why is the constructor of class A and B called, when a new instance of C is created?
Output is
B's constructor called
A's constructor called
C's constructor called

C is derived from both A and B - so before the constructor for C can be executed, the constructors for A and B must both be completed. If that wasn't the case, then the C constructor could not rely on anything that its base classes provided.
For example, suppose A contained a list of items which is created and filed from a database in its constructor. All instances of A can rely on the list being complete because the constructor has to be finished before the instance is available to the rest of the code. But C is also an A - it derives from it in the same way that "a Ford" is also "A Car" - so it may well want to access that list. When you construct an instance, the base class constructors are automatically called before the derived classes to ensure that everything is ready for action when the derived constructor starts.
For example, change your code slightly:
class A
{
public:
A() { cout << "A's constructor called" << endl; }
};
class B: public A
{
public:
B() { cout << "B's constructor called" << endl; }
};
class C: public B
{
public:
C() { cout << "C's constructor called" << endl; }
};
int main()
{
C c;
return 0;
}
and you will get:
A's constructor called
B's constructor called
C's constructor called
Because the base class constructors are all completed before the derived ones are executed.

Why wouldn't it be? A C contains parts that are a B and an A respectively, and those parts need to be constructed as well. The constructor is the feature that performs this role.

kanishk tanwar's answer has more detail, but I was writing this anyway, so here's a very whistle stop tour of why it's happening to answer your question:
In order to ensure an instance of a class is properly initialised, a constructor for the base types are always called. If you don't specify which constructor you want to call (syntax: C() : B(), A() for C's constructor), the default constructor is used. As a derived class builds on a base class, the base classes have to be constructed first.
In your case you have specified contents to your default constructor, so that is the code that is run when you instantiate C.

Related

Copy constructor needs base constructor with no arguments [duplicate]

Why aren't copy constructors chained (like default ctors or dtors) so that before the derived class's copy constructor is called, the base class's copy constructor is called? With default constructors and destructors, they are called in a chain from base-to-derived and derived-to-base, respectively. Why isn't this the case for copy constructors? For example, this code:
class Base {
public:
Base() : basedata(rand()) { }
Base(const Base& src) : basedata(src.basedata) {
cout << "Base::Base(const Base&)" << endl;
}
void printdata() {
cout << basedata << endl;
}
private:
int basedata;
};
class Derived : public Base {
public:
Derived() { }
Derived(const Derived& d) {
cout << "Derived::Derived(const Derived&)" << endl;
}
};
srand(time(0));
Derived d1; // basedata is initialised to rand() thanks to Base::Base()
d1.printdata(); // prints the random number
Derived d2 = d1; // basedata is initialised to rand() again from Base::Base()
// Derived::Derived(const Derived&) is called but not
// Base::Base(const Base&)
d2.printdata(); // prints a different random number
The copy constructor doesn't (can't) really make a copy of the object because Derived::Derived(const Derived&) can't access basedata to change it.
Is there something fundamental I'm missing about copy constructors so that my mental model is incorrect, or is there some arcane (or not arcane) reason for this design?
The copy constructor doesn't (can't) really make a copy of the object because Derived::Derived(const Derived&) can't access pdata to change it.
Sure it can:
Derived(const Derived& d)
: Base(d)
{
cout << "Derived::Derived(const B&)" << endl;
}
If you don't specify a base class constructor in the initializer list, its default constructor is called. If you want a constructor other than the default constructor to be called, you must specify which constructor (and with which arguments) you want to call.
As for why this is the case: why should a copy constructor be any different from any other constructor? As an example of a practical problem:
struct Base
{
Base() { }
Base(Base volatile&) { } // (1)
Base(Base const&) { } // (2)
};
struct Derived : Base
{
Derived(Derived&) { }
};
Which of the Base copy constructors would you expect the Derived copy constructor to call?
You can:
Derived(const Derived& d) : Base(d) {
cout << "Derived::Derived(const B&)" << endl;
}
This calls the Base copy constructor on the Base sub-object of d.
The answer for 'why' I don't know. But usually there's no answer. The committee just had to choose one option or the other. This seems more consistent with the rest of the language, where e.g. Derived(int x) won't automatically call Base(x).
That's because every constructor calls by default the default base constructor:
Derived(const Derived& d) {
cout << "Derived::Derived(const B&)" << endl;
}
will call Base().
This is defined by the standard. I for one prefer it like this rather than calling the copy constructor on the class. You can of course call it explicitly.

Virtual inheritance impact on constructor

I've started learning about virtual inheritance (and how it may solve problems of having a class derived from two parent classes with same parent). To better understand the mechanism behind it, i made a following example:
class A {
public:
A(string text = "Constructor A") { cout << text << endl; }
};
class B: public A {
public:
B(): A("A called from B") { cout << "Constructor B" << endl; }
};
class C : virtual public A {
public:
C() : A("A called from C") { cout << "Constructor C" << endl; }
};
class D : public B, public C {
public:
D() { cout << "Constructor D" << endl; }
};
I have class A, class B derived from A, class C virtually derived from A, and class D derived from B and C. In main i just form an object of class D: D d; and i get the following output
Constructor A
A called from B
Constructor B
Constructor C
Constructor D
What bothers me is, why is there "Constructor A" signalizing that it is not called by either class B or C. And why is there not "A called from C" before "Constructor C". For the latter one i know it has to do with the class C being virtually derived so i guess it does not call Constructor A again since object from class A has already been formed (twice in fact).
EDIT:
In main i just make one object type D.
int main() {
D d;
}
Firstly, since B derives from A non-virtually, D ends up with two A subobjects (as if you didn't use virtual inheritance at all).
The non-virtual A is constructed by B() (hence "A called from B"), and the virtual one prints "Constructor A" when constructed.
That's because the constructors of virtual (possibly indirect) bases are always called by the constructor of the most derived class (D), rather than by the constructors of any intermediate bases (C).
It means that : A("A called from C") in C() is ignored (since you're not constructing a standalone C). And since D() doesn't mention A in its member initializer list, the virtual A is constructed without any parameters (as if by : A()).
Also, it's worth mentioning that all virtual bases are constructed before the non-virtual ones.
So your code is guaranteed to print Constructor A before A called from B.
The problem
Your code forgot something and you still have two A objects in a D object. You can verify this claim by adding a public int test member to A and try the following code. You will get two different addresses:
D d;
cout << &d.B::test <<endl; // the non virtual A subobject of B
cout << &d.C::test <<endl; // the virtual A subobject of C
Online demo
The solution
All classes that share A virtually and that directly inherit from A must declare the virtual inheritance. So you need to correct class B:
class B: virtual public A {...} // you forgot the virtual here
The code snippets above would work as expected, and you could even address d.test without getting any ambiguity error. Online demo
Edit: The delicate construction of A
The C++ rules require each object with a virtual A sub-object to provide a constructor for A. In your case, D should provide for the virual A's construction.
Since there is no explicit constructor, D will look for a default-construct A. And it finds one, since you provide a default argument for the A constructor. It's misleading because it tells you "A constructor" when in reality it was D that used it.
If you remove this default argument, your code won't compile anymore. You then need something like this to get A properly constructed:
class A {
public:
int test;
A(string text) { cout << "A is constructed: "<<text << endl; }
};
class D : public B, public C {
public:
D() : A("Mandatory, if there is no default consructor") { cout << "Constructor D" << endl; }
};
Online demo
Why are the C++ construction rules like that ? Because when you have virtual inheritance, there is no reason that the A construction by B is drawn over the construction by C . Nor the contrary. On the other side, both B and C define how to construct their A sub-object. To solve the ambiguity in the choice of the right construction, this rule was decided. And it may be painful if the virtual class doesn't have a default constructor.
When a type has a virtual base, the virtual base gets constructed from the constructor of the most-derived type. So "Constructor A" is called from D's constructor.
A bit more detail:
#include <iostream>
struct base {
base() { std::cout << "base()\n"; }
base(int) { std::cout << "base(int)\n"; }
};
struct i1 : virtual base {
i1() : base(0) { std::cout << "i1()\n"; }
};
struct i2 : virtual base {
i2() : base(1) { std::cout << "i2()\n"; }
};
struct d : i1, i2 {
};
Now, if the code creates an object of type i1 the default constructor for i1 calls base(int), as written.
But when you create an object of type d, the constructor for d is responsible for constructing the base object. Since d does not have a default constructor, the compiler generates one that calls the default constructor for base before it calls the default constructors for i1 and i2.
int main() {
d d_obj;
return 0;
}
the output here is
[temp]$ Clang++ test.cpp
[temp]$ ./a.out
base()
i1()
i2()
[temp]$
Note that the constructors for i1 and i2 did not construct the base subobject. The compiler took care fo that: the base should only be initialized once, and the constructor for d did that.
If you want a different initialization for the base object, write that in the constructor:
d::d() : base(2) {}
adding that to the class d produces this output:
[temp]$ Clang++ test.cpp
[temp]$ ./a.out
base(int)
i1()
i2()
[temp]$

virtual inheritance in c++ misunderstood

I read that in virtual inheritance, constructors are called "from the most derived".
consider the following code. In my opinion, the most derived class here is D. then B and C and the "most-not-derived" is A.
So how come the most "Base" constructor is called first and not the "most derived"?
Thanks.
#include <iostream>
using namespace std;
struct A
{
A()
{
cout << "A default constructor" << endl;
}
};
struct B : virtual public A
{
B() : A()
{
cout << "B default constructor" << endl;
}
};
struct C : virtual public A
{
C() : A()
{
cout << "C default constructor" << endl;
}
};
struct D : public B, public C
{
D() : B(), C()
{
cout << "D default constructor" << endl;
}
};
int main()
{
D d;
}
This is the output :
A default constructor
B default constructor
C default constructor
D default constructor
UPDATE:
Ok. so consider the following code.
Notice that 10 was printed although D,B and C constructors sent 7.
Here actually the base class IS the first one that is called.
There was no chain from D to B to A.
A() was called first (actually it's default constructor). and only then B and C constructors were called.
But I read : "from the most derived."
Source : c++ virtual inheritance
the most derived here is D then B and C and only then A. So how come that A is called first without even considering the parameters B,D,C transfer to it from their constructors ?
Thanks.
The code :
#include <iostream>
using namespace std;
struct A
{
int _x;
A()
{
_x = 10;
cout << "A default constructor" << endl;
}
A(int x)
{
_x = x;
cout << "A NOT-default constructor" << endl;
}
};
struct B : virtual public A
{
B(int x=7) : A(x)
{
cout << "B constructor" << endl;
}
};
struct C : virtual public A
{
C(int x=7) : A(x)
{
cout << "C constructor" << endl;
}
};
struct D : public B, public C
{
D(int x=7) : B(x), C(x)
{
cout << "D constructor" << endl;
}
};
int main()
{
D d;
cout << d._x;
}
The output :
A default constructor
B constructor
C constructor
D constructor
10
Construction order is quite simple in C++:
You call a most-derived ctor (By initializing a variable; auto-storage-class, static, dynamic, whatever).
That ctor initializes all sub-objects:
A delegating ctor calls another most-derived-ctor.
A non-delegating ctor does the work itself:
Iff the most-derived ctor, virtual bases in left-first declaration-order. (That means arguments to the virtual-base ctor given by non-most-derived-ctors are ignored)
The other direct bases in left-first declaration-order.
The members in declaration-order.
The ctors body runs.
As your most-base ctor is for the only virtual base, its body is the first ctor-body to run, called directly by the most-derived ctor.
In general, calling virtual functions, typeid and dynamic_cast is safe, though not before the base-subobjects are all initialized: May I call a virtual function to initialize a base-class sub-object?
That means that it's the responsibility of the most derived class to initialise any virtual base sub-objects, as well as those that it immediately derives from. That is, all the base constructors are called from the most-derived constructor: the constructor for D calls the constructor for A, then B and C, and finally initialises itself. This is necessary to ensure that the shared base object is initialised just once, and before any of the classes that derive from it.
It doesn't mean that the order is from the most to least derived. As with regular inheritance, base sub-objects are always initialised first, so they're available when initialising the derived classes.
To answer your updated question, since D initialises A, it will call the default constructor unless its initialiser list contains an entry for A:
D(int x=7) : B(x), C(x) // calls A(), initialising with 10
D(int x=7) : A(x), B(x), C(x) // calls A(int), initialising with 7
Any entry for A in the initialiser list of B (or C) is only used when B (or C) is the most derived class (and so is responsibly for initialising A).
How do you propose any derived class to behave if its constructor code ran before the base class was constructed? While technically possible, it'd be entirely useless.
The behavior you observe is the only sane one, and has nothing to do with virtual inheritance.
You said
I read that in virtual inheritance, constructors are called "from the most derived".
That is true. Let me elaborate.
In your case, D is the most derived.
When you construct an instance of D, the constructors for A is called from the constructor of D since there is only instance of A for each instance of D. Constructor for A will not be called from the constructor of B or C.
When you construct an instance of B, then constructor for A is called from the constructor of B. Similarly for an instance of C.
If you had a sub-type of D,
struct E : public D
{
};
and you create an instance of E, then the constructor of A will be called from the constructor of E.
The C++ Draft Standard (N3337) says this about initialization involving virtual base classes:
12.6.2 Initializing bases and members
5 Initialization shall proceed in the following order:
— First, and only for the constructor of the most derived class as described below, virtual base classes shall be 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 class names in the derived class base-specifier-list.
That is how objects are built.
UPDATE
Check this example out:
class A{
A()
{
cout << "Constructor A"<<endl;
}
~A()
{
cout << "Destructor A"<<endl;
}
}
class B : public A{
B()
{
cout << "Constructor B"<<endl;
}
~B()
{
cout << "Destructor B"<<endl;
}
}
class C : public B{
C()
{
cout << "Constructor C"<<endl;
}
~C()
{
cout << "Destructor C"<<endl;
}
}
Creating an object of class C:
C obj;
The output will be as follows:
Constructor A
Constructor B
Constructor C
Destructor C
Destructor B
Destructor A
The reason for the execution is this:
When a class derives from another class, it derives the properties of that class. Functionalities of the derived class may or may not depend on the functionalities of the base class, but it can never be the other way. Assuming the derived class depends on the base class functionalities, it is important that the base class is properly initialized before the derived class can be initialized.
UPDATE:
When an object of C is made, he control from C constructor is transferred to it's base class' constructor, before C's constructor can execute. That's what I meant by base class first.
UPDATE:
Your question can be best answered by drawing the object relationship.
We'll have A right on the top and D at the bottom.
"in virtual inheritance, [virtual base] constructors are called from the most derived" [type's constructor]. "
By the above statement, they're asking you to start from the most derived type's constructor (D) and transverse up to the most base class' (A) constructor.
UPDATE:
#leemes has made the execution flow clearer in the comments:
It is the constructor itself which "redirects" to the base's constructor. After this returns, it continues with its own constructor. What you miss is that what is written in curly braces is not the whole implementation. It's only what comes after the call to the base ctor and initializing the member variables. Same with ctor: You write in curly braces what is to be executed before calling the ctor of member variables and then the ctor of the base.

Why aren't copy constructors "chained" like default constructors and destructors?

Why aren't copy constructors chained (like default ctors or dtors) so that before the derived class's copy constructor is called, the base class's copy constructor is called? With default constructors and destructors, they are called in a chain from base-to-derived and derived-to-base, respectively. Why isn't this the case for copy constructors? For example, this code:
class Base {
public:
Base() : basedata(rand()) { }
Base(const Base& src) : basedata(src.basedata) {
cout << "Base::Base(const Base&)" << endl;
}
void printdata() {
cout << basedata << endl;
}
private:
int basedata;
};
class Derived : public Base {
public:
Derived() { }
Derived(const Derived& d) {
cout << "Derived::Derived(const Derived&)" << endl;
}
};
srand(time(0));
Derived d1; // basedata is initialised to rand() thanks to Base::Base()
d1.printdata(); // prints the random number
Derived d2 = d1; // basedata is initialised to rand() again from Base::Base()
// Derived::Derived(const Derived&) is called but not
// Base::Base(const Base&)
d2.printdata(); // prints a different random number
The copy constructor doesn't (can't) really make a copy of the object because Derived::Derived(const Derived&) can't access basedata to change it.
Is there something fundamental I'm missing about copy constructors so that my mental model is incorrect, or is there some arcane (or not arcane) reason for this design?
The copy constructor doesn't (can't) really make a copy of the object because Derived::Derived(const Derived&) can't access pdata to change it.
Sure it can:
Derived(const Derived& d)
: Base(d)
{
cout << "Derived::Derived(const B&)" << endl;
}
If you don't specify a base class constructor in the initializer list, its default constructor is called. If you want a constructor other than the default constructor to be called, you must specify which constructor (and with which arguments) you want to call.
As for why this is the case: why should a copy constructor be any different from any other constructor? As an example of a practical problem:
struct Base
{
Base() { }
Base(Base volatile&) { } // (1)
Base(Base const&) { } // (2)
};
struct Derived : Base
{
Derived(Derived&) { }
};
Which of the Base copy constructors would you expect the Derived copy constructor to call?
You can:
Derived(const Derived& d) : Base(d) {
cout << "Derived::Derived(const B&)" << endl;
}
This calls the Base copy constructor on the Base sub-object of d.
The answer for 'why' I don't know. But usually there's no answer. The committee just had to choose one option or the other. This seems more consistent with the rest of the language, where e.g. Derived(int x) won't automatically call Base(x).
That's because every constructor calls by default the default base constructor:
Derived(const Derived& d) {
cout << "Derived::Derived(const B&)" << endl;
}
will call Base().
This is defined by the standard. I for one prefer it like this rather than calling the copy constructor on the class. You can of course call it explicitly.

Constructors order

#include <iostream>
class A
{
public:
A() { std::cout << " A ctor" << std::endl; }
A(int i) { std::cout << " A ctor i" << std::endl; }
~A() { std::cout << " A dtor" << std::endl; }
};
class B: public A
{
public:
B() : A () { std::cout << " B ctor" << std::endl; }
~B() { std::cout << " B dtor" << std::endl; }
};
class C: public A
{
public:
B _b;
C() : _b (), A () { std::cout << " C ctor" << std::endl; }
~C() { std::cout << " C dtor" << std::endl; }
};
int main ()
{
C c;
}
The output is:
A ctor
A ctor
B ctor
C ctor
C dtor
B dtor
A dtor
A dtor
What is the order of the init. list? Why, in the init. list of C, ctor of A called before ctor of B? I thought the output should be:
A ctor
B ctor
A ctor
C ctor
C dtor
A dtor
B dtor
A dtor
Thanks.
The order in which you write initializations in the initialization list is not important, the order of initialization is determined independently of that list by other rules:
First the base class is initialized. That's why in the construction of C the base class constructor A is called first. Everything that belongs to the base class is constructed in this step (base classes and member variables belonging to the base class), just like when a normal object of that base class would be constructed.
Then the member variables of the derived class are initialized, in the order in which they are declared in the class. So if there are several member variables, the order in which they are declared determines the order in which they are initialized. The order of an initialization list is not important.
Base class constructors are called before derived class constructors. This allows the derived class to use members in the base class during their construction.
During destruction, the opposite is true. Subclass destruction occurs before the base class, for exactly the same reason.
If you think about it - it makes perfect sense. The base class has no knowledge of the subclass, but the opposite is not true. This determines the ordering in order for everything to work as expected.
I think your confusion is why is C's initialization list processed right to left instead of left to write. It is because, the compiler processes parameters in "last in first out" fashion. Hence the order: First A's c'tor. Since _b is an object of B which is derived from A, base class is constructed before the derived class so A c'tor is called and then B's c'tor. And finally, C's c'tor is called. When C's object is destructed, it follows the reverse order.
If you use GNU compiler, -Wall option will help you.