Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does the C++ copy constructor behave differently when calling its child copy constructor?

Tags:

c++

I have the following toy class A and its child B:

#include <iostream>

using namespace std;

class A
{
    protected:
        int a;
    public:
        A():a(1){cout<<"A default constructor..."<<endl;}
        A(int i):a(i){cout<<"A non-default constructor..."<<endl;}
        A(const A &ao){cout<<"A copy constructor..."<<endl; a=ao.a;}
};

class B:public A
{
    private:
       int b;
    public:
       B(int i,int j):A(i),b(j){cout<<"B constructor..."<<endl;}
       //B(const B &bo){cout<<"B copy constructor... "<<endl; b=bo.b;}
       void print(){cout<<endl<<"class B, a: "<<a<<" b: "<<b<<endl<<endl;}
};

int main()
{
    B b1(3,8);
    b1.print();
    B b2=b1;
    b2.print();
}

I found that if I don't provide a copy constructor for class B, the compiler will synthesize one for me, and that one uses the copy constructor I provided for class A. However, if I do provide a copy constructor for class B, where I don't explicitly call the copy constructor for the base class A (see code), the compiler will call the default CONSTRUCTOR of class A? Why is that?

like image 904
Hailiang Zhang Avatar asked Dec 26 '22 21:12

Hailiang Zhang


2 Answers

This is the standard behavior. It's mostly for consistency: any user-defined constructor that doesn't explicitly call a specific base class constructor will call the default one. Why would the copy constructor be different?

like image 174
Luchian Grigore Avatar answered Apr 11 '23 10:04

Luchian Grigore


When you write a constructor - any constructor - for a derived class you can (and often must) explicitly initialize base class subobjects in that constructor's initializer list. If you fail to do that, then the compiler will implicitly call the default constructors for those base class subobjects, assuming they are available. This rule applies to absolutely all user-defined constructors.

This is exactly what happened in your case. You forgot to initialize base A in B::B(const B&)'s constructor, so the default constructor was used for that base. The fact that B::B(const B&) is a copy constructor makes no difference whatsoever in this case. It works that way, again, consistently for all kinds of user-defined constructors.

Now, if you do not provide a user-defined copy constructor, then the compiler will attempt to provide on implicitly. The implicitly-defined copy constructor will attempt to call copy constructors for all base classes. The language spec just says that compiler-provided copy constructor behaves that way, which is the answer to your "why" question.

like image 25
AnT Avatar answered Apr 11 '23 10:04

AnT