Oren_Zauda
Oren_Zauda

Reputation: 11

How does the compile choose which constructor to call?

This is my code.

When I delete line 11, the output is

A(0)
B(0)
A(1)

about the last line, "A(1) ", why the second constructor of class A is called?

#include <iostream>

using namespace std;

class A {
public:
   A() { cout << "A(0)" << endl; }
   A(const A& a) { cout << "A(1)" << endl; }
};

class B {
public:
    B() : a() { cout << "B(0)" << endl; }
    // B(const B& b) { cout << "B(1)" << endl; }
private:
    A a;
};

int main() {
   B object1;
   B object2 = object1;
   return 0;
}
A(0)
B(0)
A(1)

Upvotes: 1

Views: 495

Answers (5)

Vlad from Moscow
Vlad from Moscow

Reputation: 310980

The compiler for the class B (with the commented copy constructor) defines implicitly the default copy constructor that calls copy constructors for class members.

From the C++ 20 Standard (11.3.4.2 Copy/move constructors)

14 The implicitly-defined copy/move constructor for a non-union class X performs a memberwise copy/move of its bases and members...

The implicitly defined default copy constructor of the class B looks like

B( const B &b ) : a( b.a )
{
}

Here is a demonstrative program

#include <iostream>

using namespace std;

class A {
public:
   A() { cout << "A(0)" << endl; }
   A(const A& a) { cout << "A(1)" << endl; }
};

class B {
public:
    B() : a() { cout << "B(0)" << endl; }
    // An analogy of the implicitly declared copy constructor
    B(const B& b) : a( b.a ){}
private:
    A a;
};

int main() {
   B object1;
   B object2 = object1;
   return 0;
}

The program output will be the same as if to remove the copy constructor of class B that corresponds to the implicitly generated copy constructor by the compiler.

A(0)
B(0)
A(1)

Upvotes: 0

user39504
user39504

Reputation: 61

The issue you've run into has to do with thinking commenting out line 11 means you've deleted that constructor.

In C++, there are a couple of constructors that are automatically generated if you ended up using them, even if you didn't declare them yourself. The copy-constuctor, which has the same signature as the commented-out constructor in B, is one of them.

In your case, you end up first calling the default constructor for B, which first constructs it's member A using the default constructor as well. This should give the output you see, where the body of A's copy-constructor is reached before the body of B's because of member initialization ordering.

Then, you make a new object of type B using the assignment operator which implicitly calls the now-generated copy constructor of B. That means A's copy constructor gets called as well, which is a rule in how B's copy-constructor is auto generated. With A's copy-constuctor un-commented, it gets called with the printout.

Upvotes: 0

NathanOliver
NathanOliver

Reputation: 180630

When

B(const B& b) { cout << "B(1)" << endl; }

is commented out/deleted the compiler generates a copy constructor for you. This provided copy constructor will copy all of the members of the class so in this case it will stamp out a copy constructor that looks like

B(const B& copy) : a(copy.a) {}

This is why you see a's copy constructor called.

When you do not comment out/delete

B(const B& b) { cout << "B(1)" << endl; }

You do not copy a because you do not tell it to do so. What the compiler does instead is creates a default initialization for it by transforming the constructor to

B(const B& b) : a() { cout << "B(1)" << endl; }

so the default constructor is called instead of the copy constructor.

Upvotes: 7

P. PICARD
P. PICARD

Reputation: 386

Because object2 is initialized with the implicit copy constructor of B. An implicit copy constructor implicitly copy all the data members of the class, hence the call of the copy constructor of A, which prints "A(1)".

Upvotes: 0

Acorn
Acorn

Reputation: 26066

The compiler is generating a copy constructor for you, which copies the member a. In order to copy member a, it calls its copy constructor in turn, which prints A(1).

Upvotes: 1

Related Questions