Почему определяемый пользователем конструктор копирования вызывает базовый конструктор, а конструктор копирования по умолчанию — нет?

Рассмотрим следующий пример:

class A
{
    public:
        A()
        {
            cout<<"constructor A called: "<<this<<endl;  
        };
        
        A(A const& other) = default;
};

class B : public A
{
    public:
        B()
        {
            cout<<"constructor B called: "<<this<<endl;  
        };
        
        //This calls A's constructor
        B(B const& other)
        {
            cout<<"B copy constructor called: "<<this<<endl;    
        };

        //While this doesn't call A's constructor
        //B(B const& other) = default;
};

int main()
{
    B b;
    
    B b2(b);

    cout<<"b: "<<&b<<endl;
    cout<<"b2: "<<&b2<<endl;

    return 0;
}

Выход:

constructor A called: 0x7fffc2fddda8
constructor B called: 0x7fffc2fddda8
constructor A called: 0x7fffc2fdddb0
B copy constructor called: 0x7fffc2fdddb0
b: 0x7fffc2fddda8
b2: 0x7fffc2fdddb0

Почему конструктор А вызывается при копировании B? Не следует ли вместо этого вызывать конструктор копирования A?

Однако, если вы измените конструктор копирования класса B на По умолчанию, конструктор A будет не называется при копировании, что имеет смысл.

Было бы неплохо, если бы кто-то мог дать разумное объяснение, почему.

🤔 А знаете ли вы, что...
C++ обладает высокой производительностью и эффективностью в использовании ресурсов.


1
58
1

Ответ:

Решено

Why is the constructor of A is called when copying B? Shouldn't the copy constructor of A be called instead?

Нет, не должно.

Производный класс всегда должен инициализировать базовый класс. Если производный класс имеет конструктор, который явно реализуется пользователем, но он явно не вызывает конструктор базового класса в своем список инициализации членов, компилятор выполнит неявный вызов конструктора По умолчанию базового класса, несмотря ни на что типа производного конструктор. Компилятор не делает никаких предположений о намерениях пользователя при реализации производного конструктора. Если пользователь хочет, чтобы был вызван конкретный конструктор базового класса, он должен сделать этот вызов самостоятельно.

Поскольку B имеет явно реализованный конструктор копирования, в котором отсутствует список инициализации членов, компилятор инициализирует A, вызывая его конструктор По умолчанию, а не конструктор копировать.

ИОВ, это:

B(B const& other)
{
    ...
}

Эквивалентно этому:

B(B const& other) : A()
{
    ...
}

НЕ к этому, как вы думаете:

B(B const& other) : A(other)
{
    ...
}

However, if you change class B's copy constructor to be default, the constructor of A is not called when copying which makes sense.

Правильно, конструктор копирования с default будет вызывать конструктор копирования базового класса, а не его конструктор по умолчанию. Компилятор неявно реализует производный конструктор весь, поэтому он выберет для вызова соответствующий конструктор базового класса.