Почему конструкторы копирования не «связаны» как конструкторы по умолчанию или деструкторы? - PullRequest
19 голосов
/ 08 января 2012

Это может быть вопрос с очевидным ответом или дубликатом.Если так, извините, я его удалю.

Почему конструкторы копирования не связаны (например, ctors или dtors по умолчанию), чтобы перед вызовом конструктора копирования производного класса вызывался конструктор копирования базового класса?С помощью конструкторов копирования и деструкторов они вызываются в цепочке от основания к производному и от производства к базе, соответственно.Почему это не так для конструкторов копирования?Например, этот код:

class Base {
public:
    Base() : basedata(rand()) { }

    Base(const Base& src) : basedata(src.basedata) {
        cout << "Base::Base(const Base&)" << endl;
    }

    void printdata() {
        cout << basedata << endl;
    }

private:
    int basedata;
};

class Derived : public Base {
public:
    Derived() { }

    Derived(const Derived& d) {
        cout << "Derived::Derived(const Derived&)" << endl;
    }
};


srand(time(0));


Derived d1;      // basedata is initialised to rand() thanks to Base::Base()

d1.printdata();  // prints the random number

Derived d2 = d1; // basedata is initialised to rand() again from Base::Base()
                 // Derived::Derived(const Derived&) is called but not
                 // Base::Base(const Base&)

d2.printdata();  // prints a different random number

Конструктор копирования на самом деле не делает (не может) копировать объект, потому что Derived::Derived(const Derived&) не может получить доступ к basedata для его изменения.

Есть что-то фундаментальное, что я упускаю в конструкторах копирования, так что моя ментальная модель неверна, или есть какая-то непонятная (или не загадочная) причина этого дизайна?

Ответы [ 3 ]

21 голосов
/ 08 января 2012

Конструктор копирования на самом деле не (не может) сделать копию объекта, потому что Derived::Derived(const Derived&) не может получить доступ к pdata, чтобы изменить его.

Конечно, это может:

Derived(const Derived& d)
    : Base(d)
{
    cout << "Derived::Derived(const B&)" << endl;
}

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

Что касается , почему это так: почему конструктор копирования должен отличаться от любого другого конструктора? В качестве примера практической задачи:

struct Base
{
    Base() { }
    Base(Base volatile&) { } // (1)
    Base(Base const&)    { } // (2)
};

struct Derived : Base
{
    Derived(Derived&) { }
};

Какой из Base конструкторов копирования вы бы ожидали от вызова Derived конструктора копирования?

3 голосов
/ 08 января 2012

Вы можете:

Derived(const Derived& d) : Base(d) {
    cout << "Derived::Derived(const B&)" << endl;
}

Это вызывает конструктор копирования Base для подобъекта Base d.

Ответа «почему» я не знаю. Но обычно ответа нет. Комитет просто должен был выбрать один вариант или другой. Это кажется более совместимым с остальной частью языка, где, например, Derived(int x) не будет автоматически звонить Base(x).

2 голосов
/ 08 января 2012

Это потому, что каждый конструктор по умолчанию вызывает базовый конструктор по умолчанию:

Derived(const Derived& d) {
    cout << "Derived::Derived(const B&)" << endl;
}

позвонит Base().

Это определяется стандартом. Я, например, предпочитаю это, а не вызывать конструктор копирования в классе. Конечно, вы можете назвать это явно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...