我有很多公共接口(实际上是带有纯虚函数的抽象类)。只有析构函数被标记为默认值,但是删除复制/移动构造函数和复制/移动赋值操作符不是更干净吗?对于这样的“接口”,是否有一个应该删除这些构造函数/赋值操作符的指导方针?比如:
class MyInterface
{
public:
virtual ~MyInterface() = default;
MyInterface(const MyInterface&) = delete;
MyInterface(const MyInterface&&) = delete;
MyInterface& operator=(const MyInterface&) = delete;
MyInterface& operator=(const MyInterface&&) = delete;
[[nodiscard]] virtual std::string getName() const = 0;
...
};
3条答案
按热度按时间0s7z1bwu1#
复制是关于数据的。由于这里没有数据成员试图做任何关于复制/移动语义的事情是没有意义的。
mkshixfv2#
这个问题没有明确的正确答案,这取决于接口的预期用例。
C++ Core Guidelines建议显式删除继承层次结构中的复制/移动语义,以大幅降低意外object slicing的可能性。很难确信复制的对象实际上是最派生的对象。如果多态对象需要复制语义,则建议添加
virtual
函数来克隆对象。wmtdaxz33#
复制/移动分配可能会在实际代码中导致以下问题:
这是切片的示例,但是我们正在进行无意义切片分配。
理论上你可以写一个多态赋值语句:
但这种做法有意义的情况是有限的。以下是一些例子:
1.这个接口作为一个单一的固定实现的契约而存在,因此,标准的赋值语义很容易实现。
1.这个类的赋值语义被替换了,因为我们使用了嵌入式子语言技术。
对于除此之外的其他情况,在接口级别进行合理的赋值是很难证明的,因为如果两个赋值对象的类型不一致,赋值就不可能给予好的语义。
对于构造函数的情况,任何直接使用抽象类的构造函数的尝试都不可能成功。构造函数的任何使用都将在实际构造子类示例的上下文中进行。
在接口中需要做一些工作--一些杂质--这似乎是合理的。例如,如果接口的每个示例都需要集中记录其标识,则实现构造函数是有意义的。
这也是一个罕见的案例。
在999/1000种情况下,
=delete
ing是正确的选择。C++内置的对象多态性在赋值或复制/移动构造中表现不佳。这就是为什么人们用std::function
这样的版本来取代它的原因之一。