为什么 C++ 认为我的类是可复制构造的,而实际上它无法被复制构造?

💡 原文中文,约2000字,阅读约需5分钟。
📝

内容提要

C++编译器判断类是否可复制构造是基于是否存在未被删除的复制构造函数。尽管Derived类有自定义的复制构造函数,但由于Base类不可复制,实际复制会失败。如果将复制构造函数设为默认,编译器会认为Derived类不可复制。

🎯

关键要点

  • C++编译器判断类是否可复制构造是基于是否存在未被删除的复制构造函数。

  • Derived类有自定义的复制构造函数,但由于Base类不可复制,实际复制会失败。

  • 编译器认为Derived<int>是可复制构造的,但尝试复制时会发现实际上不可复制。

  • 编译器根据提供的信息判断可复制构造性,而不关心复制构造函数是否能被实例化。

  • 如果将复制构造函数设为默认,编译器会认为Derived类不可复制。

  • 不可复制性默认继承时,显式定义的未被删除的复制构造函数会被视为可用。

  • 如果基类不可复制构造,显式默认的复制构造函数会被定义为删除。

  • 要求类型完整且所有成员已定义是不合理的,因为这需要所有类方法的定义出现在头文件中。

🔎

延伸解读

编译器的判断机制

C++编译器判断类是否可复制构造的依据是是否存在未被删除的复制构造函数。即使自定义的复制构造函数无法实例化,编译器仍会认为类是可复制的。这种机制可能导致开发者在使用时产生误解,认为类可以被复制,实际却会在运行时遇到错误。

基类的影响

在C++中,基类的可复制性直接影响派生类的可复制性。如果基类不可复制,派生类的复制构造函数即使存在,也会被视为删除。这意味着在设计类时,开发者需要仔细考虑基类的特性,以避免不必要的复制构造错误。

类型完整性的问题

文章提到,要求类型完整且所有成员已定义是不合理的。这一观点强调了在大型项目中,类的实现细节可能不适合在头文件中暴露。开发者应考虑如何平衡接口的清晰性与实现的封装性,以减少潜在的编译和运行时错误。

延伸问答

C++编译器如何判断一个类是否可复制构造?

编译器通过检查类是否具有未被删除的复制构造函数来判断可复制构造性。

为什么Derived类的复制构造函数被认为是可用的?

因为Derived类有自定义的未被删除的复制构造函数,尽管它无法被实例化。

如果基类不可复制,Derived类的复制构造函数会怎样?

如果基类不可复制,Derived类的显式默认复制构造函数会被定义为删除。

为什么编译器不关心复制构造函数是否能被实例化?

编译器只关注是否存在未被删除的复制构造函数,而不考虑其能否实例化。

如何使Derived类的复制构造函数被认为是不可复制的?

可以将复制构造函数设为默认,编译器会认为Derived类不可复制。

在C++中,要求类型完整和所有成员已定义是否合理?

不合理,因为这需要所有类方法的定义出现在头文件中,增加了复杂性。

🏷️

标签

➡️

继续阅读