“我说的对吗?” “是的,按照
ForEveR的
帖子。” “有什么办法可以避免这种情况吗?” “有。只需实现一个所有多态类的基类(类似于Java和D中的
Object
类,它是所有类层次结构的根)即可实现一次性解决此问题。”
struct polymorphic {
polymorphic() = default;
virtual ~polymorphic() = default;
polymorphic(const polymorphic&) = default;
polymorphic& operator =(const polymorphic&) = default;
polymorphic(polymorphic&&) = default;
polymorphic& operator =(polymorphic&&) = default;
};
然后,任何公开派生自
polymorphic
的类都将具有一个隐式声明并定义(默认为 defaulted)的虚析构函数,除非您自己声明一个。
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的
post中引用的建议可能会在未来的标准中强制执行“五法则”。做好准备!
virtual ~my_class() = default;
这个怎么样? - Xeoprotected
。你仍然可以使用= default
默认构造函数,只需明确提及即可。 - Kerrek SBprotected
呢?它本来就无法被实例化,除非作为基类子对象,那么公共构造函数会引起什么问题呢?或者你是说,如果该类没有纯虚拟函数,而你又想将其变成“抽象”的,那么将所有构造函数设置为protected
就是实现这一点的手段? - Steve Jessop