I am studying for my final exam. I stumbled upon this question from previous years and I can't seem to fully understand whats happening.
Given this code, determine the output
#include <iostream>
using namespace std;
struct A {
A(int a): _a(a) {cout << "A::A, a=" << _a << endl;}
~A() { cout << "A::~" << endl; }
int _a;
};
struct B: public A
{
B(int b):A(b) { cout << "B::B" << endl; }
~B() { cout << "B::~" << endl; }
};
struct C: public B
{
A a;
B b;
C(int a=10, int b=20):a(a), b(a*b), B(b) {}
~C() { cout << "C::~" << endl; }
};
int main() {
C allTogetherNow;
return 0;
}
I tried to compile the code and I was given a warning:
warning: field 'b' will be initialized after base 'B'
[-Wreorder] C(int a=10, int b=20):a(a), b(a*b), B(b) {} ~C() { cout << "C::~" << endl; }
^ 1 warning generated.
and the following output:
A::A, a=20
B::B
A::A, a=10
A::A, a=200
B::B
C::~
B::~
A::~
A::~
B::~
A::~
The destruction order is kind of clear (last constructed - first destructed), but I can't seem to get ahold of the construction order/pattern.. What am I missing? A clarification of the Warning I received would be extra helpful. Also, if you could refer me to extra reading material on this particular subject.
Thank you.
The initialization order is precisely defined in the standard:
12.6.2./10: In a non-delegating constructor, initialization proceeds in the following order:
— 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.
— 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, non-static data members are initialized in the order they
were declared in the class definition (again regardless of the order
of the mem-initializers).
— Finally, the compound-statement of the
constructor body is executed.
So when you intialize C, its base class is first initialised, i.e. B with default 20 which itself requires A to be initialised first with 20. Only then is initialisation of B completed.
Then, A and B being intialized, the members of C are initalized, starting first with a with the default parameter 10, then with b(200). As b is a B, it will first require the initializeation of its own base A. Then initialisation of of b can be completed. And finally the initialisation of C is completed.
By the way, it's not part of the question but remember for your exam:
12.4/7: Bases and members are destroyed in the reverse order of the completion of their constructor.
Note about the warning:
My compiler doesn't generate this warning. There is no reason for it, as the mem-initilizer B(b) clearly uses the parameter b of your consturctor. It's only an hypotheses, but I suspect your compiler raise a false positive because b is also the name of a member (which would indeed not be initialised when calling the base). If I'm right, the following change should not raise a warning anymore:
C(int a=10, int bbb=20):a(a), b(a*bbb), B(bbb) { cout << "C::C" << endl;}
This line:
C(int a=10, int b=20):a(a), b(a*b), B(b) {}
Should be:
C(int a=10, int b=20): B(b), a(a), b(a*b) {}
In C++, the initialization order is fixed. For your type C, it will always be:
Base Class B
Member variable A a;
Member variable B b;
In your initializer list you ordered it differently. And so your compiler warned you in case you expected the initializer list's order to matter.
Related
I can't understand the output of this code. I expect 10 to be printed, but the output is 85. Can someone explain what's happening?
#include <iostream>
using namespace std;
class A
{
public:
int x=3;
A(int a) : x(a) {}
};
class B: public A
{
public:
int y = 10;
B() : A(y) {}
};
int main()
{
B b;
cout << b.x << endl;
return 0;
}
But, changing it to:
class B: public A
{
public:
int y = 10;
B(int s) : A(s) {}
};
int main()
{
B b(4);
cout << b.x << endl;
return 0;
}
It works as expected (prints 4).
This is called "undefined behavior".
Base classes are constructed first, before the class members are constructed.
In this case, you're passing the contents of an uninitialized class member to the base class's constructor.
Just because you have an initialization statement for the class member that appears on a previous line, in the .cpp file, doesn't mean that this is the initialization order. C++ does not always work this way. You're passing an uninitialized y to the base class's constructor, and then when the base class returns the subclass gets constructed, setting y to what it's initialized to.
Because of initialization order rules in first case you call A() constructor before y was assigned to 10, so value of y is undefined and depends on current value of those sizeof(int) bytes in the stack. So you initialize x with that undefined semi-random value and print it later. In second case you call B(int) with s = 4 and it successfully initializes x with 4.
As suggested by the link in #Someprogrammerdude's comment:
The order of member initializers in the list is irrelevant: the actual order of initialization is as follows:
If the constructor is for the most-derived class, virtual bases are initialized in the order in which they appear in depth-first left-to-right traversal of the base class declarations (left-to-right refers to the appearance in base-specifier lists)
Then, direct bases are initialized in left-to-right order as they appear in this class's base-specifier list
Then, non-static data member are initialized in order of declaration in the class definition.
Finally, the body of the constructor is executed
I having hard time in solving those kind of question. In an exam I going to take in a few days, they show a program in C++ which has Multiple Inheritance:
struct X {
X(){cout << "X" << endl;}
};
struct A : virtual X {
int i;
A(){cout << "A" << endl;}
};
struct B : A {
int i;
B(){cout << "B" << endl;}
virtual void f() {cout << "f" << endl;}
};
struct C : A {
int i;
C(){cout << "C" << endl;}
C(int i){cout << "C2" << endl;}
virtual void g() {cout << "g" << endl;}
};
struct D : virtual B, virtual C {
int i;
D( int i) : C(i), B() {cout << "D" << endl;}
};
And show some code from main:
D* d = new D(2014);
C* c = d;
B* b = d;
And than ask "what will be the output?" I don't need the solution, I can always
just run or debug it but I need to understand the intuition because I will not have the debugger with me on the exam. Now I know the algorithm I need to follow:
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.
— Then, direct base classes shall be initialized in declaration order
as they appear in the base-specifier-list (regardless of the order of
the mem-initializers).
— Then, nonstatic data members shall be initialized in the order they
were declared in the class definition (again regardless of the order
of the mem-initializers).
— Finally, the body of the constructor is executed. [Note: the
declaration order is mandated to ensure that base and member
subobjects are destroyed in the reverse order of initialization. ]
But I really having bad time solving them, it does not make any sense. Is it possible to show the intuition, maybe a trick or tip on solving those kind of questions? Maybe to show dark corners? Maybe somehow to write down all the classes/structs, write the vbase classes somehow in order to easy see to output?
the code is printing all the constructors. i read that constructors are not inherited when we derive a class from another class. then why creation of c is invoking constructors from b and a
class A
{
public:
A() { cout << "A's constructor called" << endl; }
};
class B
{
public:
B() { cout << "B's constructor called" << endl; }
};
class C: public B, public A // Note the order
{
public:
C() { cout << "C's constructor called" << endl; }
};
int main()
{
C c;
return 0;
}
When the document you read said constructors are "not inherited", what it means is that if class A defines a constructor A::A(int x), then a child class B will not automatically have a constructor that takes an int.
However, it's still necessary to initialize the values of the parent class; otherwise, the parent object might be in an invalid state. Constructors are used to initialize classes, so means one of the parent class' constructors must be called from the child constructor's initializer list. If the parent class has a default constructor, that one gets called by default. That's what you see in your example. If the parent doesn't provide a default constructor, you have to specify which one you want called:
class A
{
public:
A(int x) { cout << "A's constructor called" << endl; }
};
class C: public A
{
public:
C()
: A(7) /* compilation will fail without this line */
{ cout << "C's constructor called" << endl; }
};
Constructors are not inherited in the traditional sense.
Classes are what's inherited.
But in order to construct a class, its constructor needs to be called. That's its job. Hard rule, no exceptions.
When you inherit one class from a second class, constructing the first class requires the second class to be constructed too. Because the first class always contains the second class. Another hard rule, no exceptions. That's what "inheritance" means.
So, constructing the first class will invoke its constructor. Then, to construct the second class its constructor will also need to be called (actually the second class gets constructed first, then the first class's construction takes place).
And that's why both constructors will be used.
i read that constructors are not inherited when we derive a class from another class
That is correct. However, you seem to have misunderstood the meaning of that.
Let's say you have:
struct A
{
A(int) {}
};
struct B : A
{
B() : A(0) {}
};
Given the above, you won't be able to use:
B b(10);
since A(int) is not inherited by B.
That's the crux of your misunderstanding.
then why creation of c is invoking constructors from b and a
However, when you construct a B, a constructor of B is called to initialize its members. A constructor of A must also be called so that the sub-object of B that corresponds to A can be initialized.
There are couple of ways to initialize the A-part of B.
You can use a constructor of A explicitly in the member initialization list by using the syntax:
B() : A(0) {}
Leave the member initialization empty, in which case the default constructor of A is called.
B() {}
That is equivalent to:
B() : A() {}
In the example I presented, that will result in a compiler error since the default constructor of A has been deleted by providing another constructor that is different than the default constructor.
Coming back to your implementation of the default constructor of C, you have:
C() { cout << "C's constructor called" << endl; }
That is equivalent to
C() : B(), A() { cout << "C's constructor called" << endl; }
B::B() and A::A() are called when an instance of C is constructed.
Constructors are called when classes are inherited. The inheritance basically gives the derived class instance anonymous member instances of the base classes, amongst other things. These instances need to be constructed so their constructors are called.
"Constructors are not inherited" means, that class C should and will have it's own constructors, despite fact that there were constructor of B, it will not be able to use constructor of B instead of constructor of C.
And that's exactly what you get: you get constructors of all parent classes.
When you have hierarchy of classes, and construct object from one, there will be sequential construction of all his parents, starting from the base one.
And when you will destroy them, there will be sequential destruction of him and all his parents, starting from him.
By rule: first created -- last destructed.
By not inherited, C++11 standard means this
class A
{
public:
A(int x) {}
};
class B: public A
{
};
int main(void)
{
B b(5);
return 0;
}
This will fail to compile because A(int) is not inherited. You can define B to explicitly inherit A(int) by
class B: public A
{
using A::A;
};
In your case you are defining all default ctors, and which explicitly defined or not, still exist, and will be called as part of the object initialization due to your C c declaration.
C++ inheritance basically creates a class made of parts of its super-classes. For example:
class A {
public:
A() {
std::cout << "Constructor A" << '\n';
}
};
class B : public A {
public:
B() {
std::cout << "Constructor B" << '\n';
}
};
class C : public B {
public:
C() {
std::cout << "Constructor C" << '\n';
}
};
Class C is actually class C, with a class B part, and a class A part. So in order to construct class C, we need to construct each of its parts by calling the constructors for those parts. The order of these constructors is from the most-base class to the most-derived class (in this case A to C). Most-base being the class at the top of the inheritance tree, and most-derived being the class at the bottom.
This same rule applies to destructors as well. The only difference is that the destrutors are called from most-derived to most-base (C to A).
This question already has answers here:
Are parent class constructors called before initializing variables?
(7 answers)
Closed 7 years ago.
I have the following code:
class A{
public:
A(int* i){
std::cout << "in A()" << i << std::endl;
}
};
class B: public A{
public:
B(): i{new int{10}}, A{i}{
std::cout << "in B()" << std::endl;
}
private:
int* i;
};
int main()
{
B b;
}
In A constructor I have 0 (which is expected). But I want to initialize i before. Is it possible at all?
i is a data member of class B, so in order to be created, an object of class B has to be created first. So the answer, is no.
No, it is not possible since the base class initialization is always prior to derived class initialization.
C++11, 12.6.2
10 In a non-delegating constructor, initialization proceeds in the following order:
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.
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, non-static data members are initialized in the order they were declared in the class definition (again regardless of the order of the mem-initializers).
Finally, the compound-statement of the constructor body is executed.
Initialize member before base constructor. Possible?
No, that is not possible. The standard mandates that the base classes be initialized first before the members of the class are initialized.
B(): i{new int{10}}, A{i}{
std::cout << "in B()" << std::endl;
}
is transformed to:
B(): A{i}, i{new int{10}}{
std::cout << "in B()" << std::endl;
}
#include <iostream>
using namespace std;
struct A{
A() {cout << "A" << endl;}
A(int a) {cout << "A+" << endl;}
};
struct B : virtual A{
B() : A(1) {cout << "B" << endl;}
};
struct C : virtual A{
C() : A(1) {cout << "C" << endl;}
};
struct D : virtual A{
D() : A() {cout << "D" << endl;}
};
struct E : B, virtual C, D{
E(){cout << "E" << endl;}
};
struct F : D, virtual C{
F(){cout << "F" << endl;}
};
struct G : E, F{
G() {cout << "G" << endl;}
};
int main(){
G g;
return 0;
}
Program prints:
A
C
B
D
E
D
F
G
I would like to know what rules should I use to determine in what order constructors get called. Thanks.
You should follow the rules given in the C++ standard:
[C++11: 12.6.2/10]: In a non-delegating constructor, initialization proceeds in the following order:
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.
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, non-static data members are initialized in the order they were declared in the class definition (again regardless of the order of the mem-initializers).
Finally, the compound-statement of the constructor body is executed.
[ Note: The declaration order is mandated to ensure that base and member subobjects are destroyed in the reverse order of initialization. —end note ]
Virtual base subobjects are constructed first, by the most-derived class, before any other bases. This is the only way that makes sense, since the relation of the virtual bases to tbe most-derived object is not known until object construction, at runtime (hence "virtual"). All intermediate initializers for virtual bases are ignored.
So, what are your virtual bases? G derives from E and F. E derives virtually from C, which in turn derives virtually from A, so A, C are first. Next, F doesn't add any further virtual bases. Next, E has non-virtual bases B and D, in that order, which are constructed next, and then E is complete. Then comes F's non-virtual base D, and F is complete. Finally, G is complete.
All in all, it's virtual bases A, C, then non-virtual bases B, D, E and D, F, and then G itself.
You can investigate the order of constructor calls from this quote of the C++ Standard and try to trap it yourself
10 In a non-delegating constructor, initialization proceeds in the
following order: — 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. — 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, non-static
data members are initialized in the order they were declared in the
class definition (again regardless of the order of the
mem-initializers). — Finally, the compound-statement of the
constructor body is executed. [ Note: The declaration order is
mandated to ensure that base and member subobjects are destroyed in
the reverse order of initialization. —end note ]