为什么隐式复制构造函数调用基类复制构造函数而定义的复制构造函数不?

时间:2012-02-07 14:42:04

标签: c++ language-design copy-constructor

考虑一个类层次结构,其中A是基类,B派生自A

如果B中未定义复制构造函数,编译器将合成一个。调用时,此复制构造函数将调用基类复制构造函数(即使是合成的,也不会由用户提供)。

#include <iostream>

class A {
    int a;
public:
    A() {
        std::cout << "A::Default constructor" << std::endl;
    }

    A(const A& rhs) {
        std::cout << "A::Copy constructor" << std::endl;
    }
};

class B : public A {
    int b;
public:
    B() {
        std::cout << "B::Default constructor" << std::endl;
    }
};

int main(int argc, const char *argv[])
{
    std::cout << "Creating B" << std::endl;
    B b1;
    std::cout << "Creating B by copy" << std::endl;
    B b2(b1);
    return 0;
}

输出:

Creating B
A::Default constructor
B::Default constructor
Creating B by copy
A::Copy constructor

如果用户在B中定义了自己的复制构造函数,则在调用时,此复制构造函数将调用基类默认构造函数,除非明确调用基类复制构造函数存在(例如在初始化列表中)。

#include <iostream>

class A {
    int a;
public:
    A() {
        std::cout << "A::Default constructor" << std::endl;
    }

    A(const A& rhs) {
        std::cout << "A::Copy constructor" << std::endl;
    }
};

class B : public A {
    int b;
public:
    B() {
        std::cout << "B::Default constructor" << std::endl;
    }
    B(const B& rhs) {
        std::cout << "B::Copy constructor" << std::endl;
    }
};

int main(int argc, const char *argv[])
{
    std::cout << "Creating B" << std::endl;
    B b1;
    std::cout << "Creating B by copy" << std::endl;
    B b2(b1);
    return 0;
}

输出:

Creating B
A::Default constructor
B::Default constructor
Creating B by copy
A::Default constructor
B::Copy constructor

我的问题是,为什么用户定义的复制构造函数不会将基类复制构造函数作为默认行为调用?

3 个答案:

答案 0 :(得分:9)

所有基本子构造函数都调用父默认构造函数。这就是标准的定义方式。正如您所指出的,如果您希望派生类B调用A的复制构造函数,则必须明确要求它

#include <iostream>

class A {
int a;
public:
A() {
    std::cout << "A::Default constructor" << std::endl;
}

A(const A& rhs) {
    std::cout << "A::Copy constructor" << std::endl;
}
};

class B : public A {
int b;
public:
B() {
    std::cout << "B::Default constructor" << std::endl;
}
B(const B& rhs):A(rhs) {
    std::cout << "B::Copy constructor" << std::endl;
}
};

int main(int argc, const char *argv[])
{
std::cout << "Creating B" << std::endl;
B b1;
std::cout << "Creating B by copy" << std::endl;
B b2(b1);
return 0;
}

这是因为编译器无法知道每个不同的构造函数应该调用哪个父构造函数,因此我们有默认构造函数对于所有其他构造函数,您必须明确说明它们。 / p>

输出:

Creating B
A::Default constructor
B::Default constructor
Creating B by copy
A::Copy constructor
B::Copy constructor

答案 1 :(得分:7)

这就是隐式复制构造函数的定义方式(调用默认值没有意义)。一旦定义了任何构造函数(复制或其他),它的正常自动行为就是调用默认的父构造函数,因此为一个特定的用户定义的构造函数更改它是不一致的。

答案 2 :(得分:2)

简单(可能是陈腐的)答案是因为你没有告诉它。由于您正在编写派生的复制构造函数,因此您可以完全控制其行为方式。未能指定对基类的调用,编译器通过调用基类的默认构造函数生成初始化基类的代码。