Why aren't copy constructors “chained” like default constructors or destructors?

 ̄綄美尐妖づ 提交于 2019-12-03 04:22:39

问题


This might be a question with an obvious answer or a duplicate. If so, sorry, I'll delete it.

Why aren't copy constructors chained (like default ctors or dtors) so that before the derived class's copy constructor is called, the base class's copy constructor is called? With copy constructors and destructors, they are called in a chain from base-to-derived and derived-to-base, respectively. Why isn't this the case for copy constructors? For example, this code:

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

The copy constructor doesn't (can't) really make a copy of the object because Derived::Derived(const Derived&) can't access basedata to change it.

Is there something fundamental I'm missing about copy constructors so that my mental model is incorrect, or is there some arcane (or not arcane) reason for this design?


回答1:


The copy constructor doesn't (can't) really make a copy of the object because Derived::Derived(const Derived&) can't access pdata to change it.

Sure it can:

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

If you don't specify a base class constructor in the initializer list, its default constructor is called. If you want a constructor other than the default constructor to be called, you must specify which constructor (and with which arguments) you want to call.

As for why this is the case: why should a copy constructor be any different from any other constructor? As an example of a practical problem:

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

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

Which of the Base copy constructors would you expect the Derived copy constructor call?




回答2:


You can:

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

This calls the Base copy constructor on the Base sub-object of d.

The answer for 'why' I don't know. But usually there's no answer. The committee just had to choose one option or the other. This seems more consistent with the rest of the language, where e.g. Derived(int x) won't automatically call Base(x).




回答3:


That's because every constructor calls by default the default base constructor:

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

will call Base().

This is defined by the standard. I for one prefer it like this rather than calling the copy constructor on the class. You can of course call it explicitly.



来源:https://stackoverflow.com/questions/8773048/why-arent-copy-constructors-chained-like-default-constructors-or-destructors

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!