0

I have always thought that base class constructors/destructors/friends are not inherited by derived class. This link confirms this : http://www.geeksforgeeks.org/g-fact-4/.

I was also aware that we can write base class constructors in the initialization list of derived class initializer list.

Having said that: I tried to check my skills today about it. But I failed to guess the output of this program.

#include<iostream> class A { int x, y; public: A(int a = 0, int b = 0) : x(a), y(b) { std::cout << "A ctor called" << std::endl; } void print_A() { std::cout << "x = " << x << std::endl; std::cout << "y = " << y << std::endl; } }; class B : public A { int z; public: // I knew that A member can be initilized like this. B(int a = 0, int b = 0, int c = 0) : z(a), A(b, c) { std::cout << "C ctor called" << std::endl; // I was not aware about that. A(b, c); } void print_B() { std::cout << "z = " << z << std::endl; } }; int main() { B b(1, 2, 3); b.print_A(); b.print_B(); } 

Output :

A ctor called C ctor called A ctor called x = 2 y = 3 z = 1 

Couple of questions:

  • If constructors/desctructors/friends are not inherited from base, how can class 'B' is able to access constructor of class 'A' here.

  • How come you get this output? How come two constructors of 'A' have been called.

4 Answers 4

3

Your understanding is faulty. This:

// I was not aware about that. A(b, c); 

doesnt initialise the A member of B, it (notionally at least) creates a temporary, nameless local variable in the body of the constructor, somewhat analogous to if you had said:

 A a(b, c); 

The constructor for A is a public member, so anything can call it.

Sign up to request clarification or add additional context in comments.

Comments

1

If constructors/desctructors/friends are not inherited from base, how can class 'B' is able to access constructor of class 'A' here?

"Not inherited" does not mean "inaccessible to the derived class". A derived class can certainly reference a base constructor. B's constructor does it twice:

  • The first access is in the initialization list
  • The second access is in the body of B's constructor; it creates a temporary object

Inheriting a constructor would mean that users of B would be able to access B(int, int), which they cannot do*.

It seems like a constructor call. Why does it create a temporary object?

Consider this method:

void foo(const A& a); 

A common way is to call it like this:

A a(1, 2); foo(a); 

but C++ also lets you call it without creating A on a separate line:

foo(A(1, 2)); 

In this case C++ creates a temporary object, and passes foo a reference to it. When you write

A(1, 2) 

C++ also creates a temporary object for you by calling its constructor.

How come two constructors of 'A' have been called.

The constructor is invoked twice; that is why you get the output.

* C++11's using mechanism allows you to achieve an effect very similar to constructor inheritance, provided that you follow specific rules.

Comments

0

the constructor is called by the every time A(b, c) is called;

you are calling it on line

B(int a = 0, int b = 0, int c = 0) : z(a), A(b, c) { 

and you are calling it inside the b constructor

// I was not aware about that. A(b, c); 

the code works as intended

Comments

0

If constructors/desctructors/friends are not inherited from base, how can class 'B' is able to access constructor of class 'A' here.

You mean on these lines?

 // I was not aware about that. A(b, c); 

It isn't "accessing the constructor" in the sense you think. It just creates (and immediately discards) an anonymous temporary A in the body of the constructor function.

How come you get this output? How come two constructors of 'A' have been called.

Because you created two instances of A: the base-class subobject of B b, and the anonymous temporary.

Here's an easy experiment to verify this, with the following logging:

// in A A(int a = 0, int b = 0) : x(a), y(b) { std::cout << "A::A @" << static_cast<void*>(this) << std::endl; } ~A() { std::cout << "A::~A @" << static_cast<void*>(this) << std::endl; } // in B B(int a = 0, int b = 0, int c = 0) : z(a), A(b, c) { std::cout << "B::B @" << static_cast<void*>(this) << std::endl; A(b, c); } ~B() { std::cout << "B::~B @" << static_cast<void*>(this) << std::endl; } 

I get output something like

A::A @0xffec7054 B::B @0xffec7054 A::A @0xffec704c A::~A @0xffec704c x = 2 y = 3 z = 1 B::~B @0xffec7054 A::~A @0xffec7054 

See that the instance address of the second A::A is different from the first (so it's a different object), and it's followed by an A::~A (because the anonymous temporary goes immediately out of scope).


Notes:

  1. If you could "call the constructor" as you suggested originally, it would look something like

    auto subobject = static_cast<A*>(this); new (subobject) A(b, c); 

    and would be very wrong. The A subobject of b was completely constructed when it's own constructor completed, before the body of B's constructor starts. You can't just re-create a new object in the same space, what would happen to the old one?

    This may seem trivial, but for objects with dynamically-allocated resources, it would be a serious bug. It's not allowed.

  2. You wrote your initializer list : z(a), A(b, c), but should be aware the base-class subobject will be constructed before the derived-class members are initialized. That is, those two things will happen in the opposite order to what you wrote. It's not (necessarily) an error, but it's worth knowing.

2 Comments

But why, It seems like a constructor call. Why does it create a temporary object.
Creating an object does call the constructor. That's how the object is constructed. And A(b,c) is just the same as A a(b,c) except you didn't give the new object a name. Compare the expression new A(b,c) which also constructs an object in newly-allocated memory (in that case the resulting A* pointer will usually be saved in a named variable, but the object itself doesn't have a name).

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.