为什么复制构造函数不像默认构造函数或析构函数那样“链接”?

时间:2012-01-07 20:55:02

标签: c++ constructor copy-constructor

这可能是一个明显答案或重复的问题。如果是,抱歉,我会删除它。

为什么链接复制构造函数(如默认ctors或dtors),以便在调用派生类的复制构造函数之前调用基类的复制构造函数?对于复制构造函数和析构函数,它们分别在从base-to-derived和derived-to-base的链中被调用。为什么复制构造函数不是这种情况?例如,此代码:

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 个答案:

答案 0 :(得分:21)

  

复制构造函数不能(不能)真正复制对象,因为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复制构造函数?

答案 1 :(得分:3)

你可以:

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

这会调用Base Base子对象上的d副本构造函数。

“为什么”我不知道的答案。但通常没有答案。委员会只需选择一种方案或另一种方案。这似乎与语言的其他部分更加一致,例如Derived(int x)不会自动调用Base(x)

答案 2 :(得分:2)

那是因为每个构造函数默认调用默认的基础构造函数:

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

将致电Base()

这是由标准定义的。我喜欢这样,而不是在类上调用复制构造函数。你当然可以明确地称之为。