多态类中没有隐式复制构造函数
No implicit copy constructor in polymorphic class?
在 C++11 中,多态类(具有 virtual
个成员方法的类)应该/必须具有 virtual
析构函数(以便基类指针上的delete
执行预期)。但是,声明析构函数显式弃用复制构造函数的隐式生成(尽管编译器可能不会广泛实现这一点),因此也会弃用默认构造函数的隐式生成。因此,要使任何多态类不被弃用,它必须具有这些成员
virtual ~polymorphic_class() = default;
polymorphic_class() = default;
polymorphic_class(polymorphic_class const&) = default;
显式定义,即使它们是微不足道的。我说的对吗?(这不是很烦人吗?这背后的逻辑是什么?有什么办法可以避免这种情况吗?
我说的对吗?
是的,根据ForEveR的帖子。
有什么办法可以避免这种情况吗?
是的。只需为所有多态类实现一个基(类似于 Java 中的类 Object
,它是所有类层次结构的根,只需执行此操作一次):
struct polymorphic {
polymorphic() = default;
virtual ~polymorphic() = default;
polymorphic(const polymorphic&) = default;
polymorphic& operator =(const polymorphic&) = default;
// Those are not required but they don't harm and are nice for documentation
polymorphic(polymorphic&&) = default;
polymorphic& operator =(polymorphic&&) = default;
};
然后,任何从 polymorphic
公开派生的类都将有一个隐式声明和定义(作为默认)的虚拟析构函数,除非您自己声明一个。
class my_polymorphic_class : public polymorphic {
};
static_assert(std::is_default_constructible<my_polymorphic_class>::value, "");
static_assert(std::is_copy_constructible <my_polymorphic_class>::value, "");
static_assert(std::is_copy_assignable <my_polymorphic_class>::value, "");
static_assert(std::is_move_constructible <my_polymorphic_class>::value, "");
static_assert(std::is_move_assignable <my_polymorphic_class>::value, "");
这背后的逻辑是什么?
我不能确定。以下只是猜测。
在 C++98/03 中,三法则说,如果一个类需要用户定义复制构造函数、复制赋值运算符或析构函数,那么它可能需要用户定义这三个。
遵守三法则是一种很好的做法,但这只不过是一个指导方针。标准不会强制这样做。为什么不呢?我的猜测是,人们是在标准发布后才意识到这一规则的。
C++11 引入了移动构造函数和移动赋值运算符,将三法则变成了五法则。事后看来,委员会希望执行五人规则。这个想法是:如果五个特殊函数中的任何一个是用户声明的,那么其他函数(析构函数除外)将不会隐式默认。
然而,委员会不想通过执行这条规则来破坏几乎所有C++98/03代码,然后决定只部分地这样做:
如果移动构造函数或移动赋值运算符是用户声明的,则将删除除析构函数之外的其他特殊函数。
如果五个特殊函数中的任何一个是用户声明的,则不会隐式声明移动构造函数和移动赋值运算符。
对于 C++98/03 格式正确的代码,移动构造函数和移动赋值运算符都不会用户声明,规则 1 不适用。因此,当使用符合 C++11 的编译器进行编译时,C++98/03 格式良好的代码不会因此规则而无法编译。(如果是这样,那是出于其他一些原因。
此外,根据规则 2,移动构造函数和移动赋值运算符不会隐式声明。这也不会破坏C++98/03格式良好的代码,因为他们从未期望过移动操作的声明。
OP中提到的弃用以及在ForEveR的帖子中引用的,表明未来的标准可能会强制执行五人规则。做好准备!
你是对的,将来的标准应该是这样,但现在它只是被弃用了,所以每个编译器都应该支持隐式声明的复制构造函数,当析构函数现在是虚拟的。
N3376 12.8/7
如果类定义未显式声明复制构造函数,则隐式声明一个。如果类定义声明移动构造函数或移动赋值运算符,隐式声明的复制构造函数定义为已删除;否则,它被定义为默认值 (8.4)。如果类具有用户声明的复制赋值运算符或用户声明的析构函数。
在我看来,您无法为此采取任何解决方法。
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 为什么在C++中使用私有复制构造函数与删除复制构造函数
- 当从函数参数中的临时值调用复制构造函数时
- 如果有一个模板构造函数只有一个泛型参数,为什么我必须有一个复制构造函数
- 为什么需要复制构造函数,在哪些情况下它们非常有用
- 使用仅使用一次的变量调用的复制构造函数.这可能是通过调用move构造函数进行编译器优化的情况吗
- 为什么类中的ostringstream类型的成员会导致";调用隐含删除复制构造函数";错误
- 复制构造函数、赋值运算符C++
- std::ofstream 作为类成员删除复制构造函数?
- 复制构造函数C++无法正确复制指针
- 关于复制构造函数的一个棘手问题
- 为什么调用复制构造函数而不是移动构造函数?
- 填充上编译器生成的复制构造函数之间的不一致
- C++ 对象指针数组的复制构造函数
- C++ 基本 CTOR 说明 - 为什么不调用赋值/复制构造函数
- 防止在复制构造函数中隐式调用基构造函数
- 为用户定义的类正确调用复制构造函数/赋值运算符
- 具有已删除移动和复制构造函数的类的就地构造
- 复制构造函数隐式转换问题
- 复制构造函数中的递归调用