Рассмотрим следующий пример:
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++ обладает высокой производительностью и эффективностью в использовании ресурсов.
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
будет вызывать конструктор копирования базового класса, а не его конструктор по умолчанию. Компилятор неявно реализует производный конструктор весь, поэтому он выберет для вызова соответствующий конструктор базового класса.