gpt4 book ai didi

c++ - c++ 接口(interface)必须遵守五法则吗?

转载 作者:IT老高 更新时间:2023-10-28 23:02:14 29 4
gpt4 key购买 nike

定义接口(interface)类时,声明实例化方法的正确方法是什么?

出于显而易见的原因,抽象基类必须具有虚拟析构函数。但是,随后会给出以下编译警告:“'InterfaceClass' 定义了非默认析构函数,但未定义复制构造函数、复制赋值运算符、移动构造函数或移动 赋值运算符”,即“五法则”。

我理解为什么一般应该遵守“五法则”,但它仍然适用于抽象基类或接口(interface)吗?

我的暗示是:

class InterfaceClass
{
// == INSTANTIATION ==
protected:
// -- Constructors --
InterfaceClass() = default;
InterfaceClass(const InterfaceClass&) = default;
InterfaceClass(InterfaceClass&&) = default;

public:
// -- Destructors --
virtual ~InterfaceClass() = 0;


// == OPERATORS ==
protected:
// -- Assignment --
InterfaceClass& operator=(const InterfaceClass&) = default;
InterfaceClass& operator=(InterfaceClass&&) = default;


// == METHODS ==
public:
// Some pure interface methods here...
};



// == INSTANTIATION ==
// -- Destructors --
InterfaceClass::~InterfaceClass()
{
}

这是正确的吗?这些方法应该是 = delete 吗?是否有某种方法可以声明析构函数是虚拟纯的,同时又以某种方式保持默认?

即使我将析构函数声明为:virtual ~InterfaceClass() = default;,如果我没有显式默认其他四个,我也会得到相同的编译器警告。

Tl;dr:什么是满足接口(interface)类“五规则”的正确方法,因为用户必须定义​​一个虚拟析构函数。

感谢您的宝贵时间和帮助!

最佳答案

Is this correct? Should these methods be = delete instead?

您的代码似乎正确。当您尝试以多态方式复制派生类时,需要将特殊的复制/移动成员函数定义为默认和 protected 。考虑这个额外的代码:

#include <iostream>

class ImplementationClass : public InterfaceClass
{
private:
int data;
public:
ImplementationClass()
{
data=0;
};
ImplementationClass(int p_data)
{
data=p_data;
};
void print()
{
std::cout<<data<<std::endl;
};
};


int main()
{
ImplementationClass A{1};
ImplementationClass B{2};
InterfaceClass *A_p = &A;
InterfaceClass *B_p = &B;
// polymorphic copy
*B_p=*A_p;
B.print();
// regular copy
B=A;
B.print();
return 0;
}

并考虑在 InterfaceClass 中定义特殊复制/移动成员函数的 4 个选项。

  1. 复制/移动成员函数 = 删除

在您的 InterfaceClass 中删除特殊的复制/移动成员函数,您将防止多态复制:

*B_p = *A_p; // would not compile, copy is deleted in InterfaceClass

这很好,因为多态复制将无法复制派生类中的数据成员。

另一方面,您也会阻止正常复制,因为如果没有基类复制赋值运算符,编译器将无法隐式生成复制赋值运算符:

B = A; //  would not compile either, copy assignment is deleted in ImplementationClass 
  1. 复制/移动特殊成员函数公开

使用复制/移动特殊成员函数作为默认和公共(public),(或不定义复制/移动成员函数),正常复制可以工作:

B = A; //will compile and work correctly

但是会启用多态复制并导致切片:

*B_p = *A_p; // will compile but will not copy the extra data members in the derived class. 
  1. 复制/移动未定义的特殊成员函数

如果未定义 move© 特殊成员函数,则与复制相关的行为类似于 2:编译器将隐式生成已弃用的复制特殊成员(导致多态切片)。但是在这种情况下,编译器不会隐式生成移动特殊成员,因此将在可以移动的地方使用复制。

  1. protected 复制/移动成员函数(您的提议)

使用特殊的复制/移动成员函数作为默认和 protected ,如在您的示例中,您将防止多态复制,否则会导致切片:

*B_p = *A_p; // will not compile, copy is protected in InterfaceClass

但是,编译器会为 InterfaceClass 显式生成一个默认的复制赋值运算符,而 ImplementationClass 将能够隐式生成它的复制赋值运算符:

B = A; //will compile and work correctly

所以你的方法似乎是最好和最安全的选择

关于c++ - c++ 接口(interface)必须遵守五法则吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49961811/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com