我定义了一个非复制构造函数,是否仍会隐式定义复制构造函数?

42

一个已经定义了用户自定义构造函数但不是拷贝构造函数的,能否调用(隐式)默认拷贝构造函数

如果可能的话,那么假设我们显式定义了类的拷贝构造函数,现在可以调用(隐式)默认构造函数吗?


http://stackoverflow.com/questions/10854948/when-is-default-constructor-generated-in-c - BoBTFish
复制构造函数和构造函数是不同的,它们在不同的情况下被调用,一个不会隐藏另一个。 - MarsRover
问题是,为什么你想要这样做。通常情况下,你会定义自己的复制构造函数,因为默认的构造函数不够用 - 那么你为什么还想调用它呢? - Björn Pollex
同时拥有默认和重载的复制构造函数是不明确的。 - Mark Garcia
3个回答

110

首先,让我们明确一下我们的词汇。默认构造函数是可以不带任何参数调用的构造函数。复制构造函数是可以通过一个相同类型的单个参数调用的构造函数。基于此,"默认复制构造函数"将具有类似以下签名的构造函数:

class MyClass
{
public:
    static MyClass ourDefaultInstance;
    //  default copy constructor...
    MyClass( MyClass const& other = ourDefaultInstance );
};
一些误解,我认为你询问的是隐式声明或隐式定义的复制构造函数;一种复制构造函数,其声明或定义由编译器隐含提供。除非您提供可视为复制构造函数的声明,否则编译器将始终提供该声明。提供其他构造函数不会阻止编译器隐含声明复制构造函数。
这与默认构造函数不同 - 任何用户定义的构造函数都将防止编译器隐含声明默认构造函数。这意味着如果您有一个用户定义的复制构造函数,编译器将不会隐含声明默认构造函数。
第二个重要的点是您不调用构造函数。编译器在某些明确定义的上下文中调用它们:主要是变量定义和类型转换。编译器只能调用已声明的构造函数(包括那些隐含声明的构造函数)。因此,如果您有一个用户定义的构造函数(复制或其他类型),并且没有定义默认构造函数,则编译器只能在具有调用参数的上下文中调用它。
总之,我认为您的问题是:即使类具有其他用户定义的构造函数,编译器也会提供隐式复制构造函数,前提是这些构造函数都不能被认为是复制构造函数。如果您提供了一个用户定义的复制构造函数,则编译器将不会提供隐式声明的默认复制构造函数。

5
@James Kanze: 非常好的解释,我指的是编译器隐式定义的默认复制构造函数。 - sourabh912
同意。+1。 “默认复制构造函数”是一个采用默认值的复制构造函数,很好!这引发了一个有趣的问题:如何构造“ourDefaultInstance”。默认构造它将是未定义行为。我想需要一个非默认构造函数。 - David Hammen
@DavidHammen 是的。我只展示了我要表达的最小必需部分,但是每当你声明一个复制构造函数时,你必须同时声明其他构造函数,否则你将永远无法构造任何东西进行复制。在这种情况下,是的,尝试默认构造ourDefaultInstance将是未定义行为。 - James Kanze
@DavidHammen “默认拷贝构造函数”是一个默认构造函数(可以不带参数调用)和一个拷贝构造函数(可以用同类型的一个参数调用)。你可以添加任意多个额外的参数,只要它们都有默认值。 - James Kanze
4
刚刚偶然看到这个。关于回答中的最后一句话:根据这个参考文献,在C++11中,即使存在用户定义的复制构造函数,使用关键字“default”仍然可以强制生成隐式复制构造函数。 - j0rre

14

http://www.cplusplus.com/articles/y8hv0pDG/

如果您没有定义拷贝构造函数,那么默认的拷贝构造函数就会存在。因此,如果您没有定义拷贝构造函数,您可以调用默认的拷贝构造函数;但是,如果您在类中定义了拷贝构造函数,您将无法调用默认的拷贝构造函数。


2
我不理解你最后的陈述 - 你能否整理一下这个回答? - Nim
1
Nim默认情况下提供复制构造函数。对于某些实例,您可能希望定义自己的复制构造函数,例如仅从10个数据成员中复制一两个数据成员,或进行代码优化。如果您定义自己的复制构造函数,则编译器将不会为该类提供默认的复制构造函数。还可以通过定义它(我不确定这个过程)完全删除复制构造函数,以确保其不可用。希望这能澄清问题? - Shane
1
@Shane:后者并不是真的。你可以将其删除,但只有在C++11中才能这样做。而且,它不是通过定义来完成的,而是通过声明为=delete来完成的。 - MSalters
@MSalters:啊,听起来是对的。就像我说的,不确定这个过程,感谢你为我澄清了这一点。 - Shane
1
@MSalters,在 C++11 之前,你可以声明一个 private 的复制构造函数来阻止其他人使用它。或者,甚至只是声明它但不实现!T(const T&); - Aaron McDaid

3

不存在所谓的默认复制构造函数。有默认构造函数和复制构造函数,它们是不同的事情。

隐式定义的复制构造函数(我认为这就是你所说的“默认复制构造函数”)将使用它们的复制构造函数而不是默认构造函数来复制类类型的非静态成员。当你没有定义自己的复制构造函数时,隐式定义的复制构造函数会被使用。


@ChristianRau 请查看此文章 http://codewrangler.home.comcast.net/~codewrangler/tech_info/ctor_init.html - user1280616
1
是的,它并没有提到复制构造函数。只是说如果有任何构造函数存在,则不会生成默认构造函数。我看到你可能误解了OP的术语“默认复制构造函数”而将其理解为默认构造函数(像其他人似乎也这样做了),但另一方面,我无法想象如何不将其理解为隐式生成的复制构造函数。对于复制构造函数,你的第一个段落是完全错误的,因为如果不存在复制构造函数,它们总是会被生成,就像你在最后一段中所说的那样。 - Christian Rau
@ChristianRau 你最好问一下原作者第二段和第三段 - P.P
@ChristianRau 这取决于他在第一段中想要表达什么。一旦为类定义了任何构造函数,就不再生成默认构造函数。这是他的意思吗(其中“所有默认的”表示“默认构造函数”,而“变得不可用”表示“没有隐式声明的构造函数”)?还是他正在制造他在第二段中解释的混淆? - James Kanze
@KingsIndian 哈哈,发现得好。事实上,原作者也引起了混淆。 - Christian Rau
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接