Constructor call in inherited classes - c++

Consider the following code:
class A {
public:
int a;
};
class B : public A {
public:
B() { std::cout << "B[" << a << "]" << std::endl; }
};
class C : public B {
public:
C() { std::cout << "C[" << a << "]" << std::endl; }
};
int main(int argc, char *argv[]) {
B();
std::cout << std::endl;
C();
}
And its output -- program compiled with g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3:
B[0]
B[-2097962768]
C[-2097962768]
The only way I found to get the second call -- C() -- to have its values initialized was adding an explicit call to the constructors, like:
class B : public A {
public:
B() : A() { std::cout << "B[" << a << "]" << std::endl; }
};
class C : public B {
public:
C() : B() { std::cout << "C[" << a << "]" << std::endl; }
};
Although I understand that calling the default constructor of each former class will initialize the values, I'm not able to see what is being called when nothing is specified.
Isn't the default constructor what is called by default -- hence its handle?

With your original code
class A {
public:
int a;
};
class B : public A {
public:
B() { std::cout << "B[" << a << "]" << std::endl; }
};
the members of A are not initialized, because you have not specified any initialization. And generally, in C++ you don't pay for what you don't need. So, you don't get initialization by default for POD members (however, you do get it for members that have constructors, because there the initialization is specified).
In your subsequent "explicit constructor call" code
class B : public A {
public:
B() : A() { std::cout << "B[" << a << "]" << std::endl; }
};
you have specified value initialization of the A base class sub-object. Effectively this reduces to zero-initialization.
It's the same difference as
A* p = new A;
versus
A* p = new A();
The latter value-initializes the object.
Standardese…
C++11 §8.5/10:
“An object whose initializer is an empty set of parentheses, i.e., (), shall be value-initialized.”
C++11 §8.5./7:
“To value-initialize an object of type T means:
— if T is a (possibly cv-qualified) class type (Clause 9) with a user-provided constructor (12.1), then the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
— if T is a (possibly cv-qualified) non-union class type without a user-provided constructor, then the object is zero-initialized and, if T’s implicitly-declared default constructor is non-trivial, that constructor is called.
— if T is an array type, then each element is value-initialized;
— otherwise, the object is zero-initialized.
An object that is value-initialized is deemed to be constructed and thus subject to provisions of this International Standard applying to “constructed” objects, objects “for which the constructor has completed,” etc., even if no constructor is invoked for the object’s initialization.”
It is perhaps worth noting that value initialization was not part of the original C++98. It was introduced in C++03, by Andrew Koenig (of "Koenig look-up" fame) in order to deal with some severe problems of unexpected effects of pure default-initialization. Which is what the () initializer bought you in C++98.

Edit my original answer was quite wrong, so I have edited it heavily.
If you want to guarantee that A::a is zero-initialized in the absence of value initialization calls such as
A a1; //
or
B() { .... }
then you can give A a constructor and do the initialization there:
class A {
public:
A() : a() {} // value initialization of a, means zero initialization here.
int a;
};
Otherwise, explicitly calling A() in B and C's constructors performs the value initialization.
// value initialization of A sub-object leads to zero initialization of A::a
B() : A() {}
This also works for initialization of an A instance:
A a1 = A();

Related

Different behaviour list initialization when specifying constructor

I have code like this for example :
class A {
public:
int x;
A() {
std::cout << "Constructor Called !" << std::endl;
}
A(int y):x(y) {
std::cout << "Constructor Param Called !" << std::endl;
}
A(const A& copy) {
std::cout << "Copy Constructor Called !" << std::endl;
}
}
class B {
public:
A value;
//B(const A& val) : value(val){}
}
int main(){
B b { A(22)};
}
If i comment out the B constructor the output is just "Constructor Param Called", but if i uncomment B constructor the output would be "Constructor Param Called" & "Copy Constructor Called". My questions :
Why is the output different if i commented out the constructor ? (I've read about aggregate class & aggregate initialization, is this it ?)
What's the difference between aggregate initialization & direct initialization ?
When you remove the user-provided constructor for B, B becomes an aggregate. So aggregate-initialization is performed where each element of the class is copy-initialized from the elements of the initializer list. Since A(22) is a prvalue of the same class as B's element, copy-elision takes place where the value is stored directly into the object without any calls to the copy-constructor. This is new as of C++17.
When you declare the constructor for B, it is no longer an aggregate, so constructors are considered when you're doing an initialization.
Direct-intialization just means there is no = sign when you're initializing an object. Aggregate-initialization is what takes place when you're initializing an aggregate, and you can take a look at the definition on cppreference for that.

Explicitly defaulted destructor disables default move constructor in a class

I have run into a problem that a move constructor of a superclass did not get invoked properly when its subclass has an explicitly defaulted destructor. The move constructor does get invoked when the destructor is implicitly defaulted (not provided at all in the supclass definition).
I am aware of the constraints that the compilers should apply to default move constructors. Yet, I have been by all means sure that the compiler should not discriminate between explicitly/implicitly defaulted destructors (or constructors as well) when applying these rules. In other words, explicitly defaulted destructor should not be treated as user-defined one (in contrast to an empty user-defined destructor ).
Tested with MSVC 2019 only.
Am I or MSVC right here?
#include <iostream>
class A {
public:
A() = default;
A(const A&) { std::cout << "Auch, they'r making copy of me(?!)" << std::endl; }
A(A&&) { std::cout << "I am moving :)" << std::endl; }
~A() = default;
};
class B : public A {
public:
};
class C : public A {
public:
C() = default;
};
class D : public A {
public:
~D() = default;
};
class E : public A {
public:
E() = default;
E(const E&) = default;
E(E&&) = default;
~E() = default;
};
int main()
{
std::cout << "\n---- A ----\n" << std::endl;
A a;
A a2(std::move(a));
std::cout << "\n---- B ----\n" << std::endl;
B b;
B b2(std::move(b));
std::cout << "\n---- C ----\n" << std::endl;
C c;
C c2(std::move(c));
std::cout << "\n---- D ----\n" << std::endl;
D d;
D d2(std::move(d));
std::cout << "\n---- E ----\n" << std::endl;
E e;
E e2(std::move(e));
}
EXPECTED: Display "I am moving :)" in all cases
ACTUAL : Displays "Auch, they'r making copy of me(?!)" in case D
When you declare a defaulted destructor in D, you disable the compiler-generated move constructor and move assignment operator in D (!), not the base class version. This is why you get the expected output with E, where you override the defaulted operation by the compiler by explicitly = defaulting the special member functions. The compiler-generated move constructor does the right thing for movable base class types, so follow the rule of five and = default the special member functions for D.
Have a look at the table in this answer. It's a very useful reference to be kept under the pillow.

Constructors calling in c++ (inherited classes)

#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.

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.

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.