GMock测试接口与Rule of 5的合规性及代码冗余疑问
C++接口类遵循Rule of 3/5的疑问及解答
问题描述
我定义了一个用于GMock测试的接口类:
class Turtle { ... virtual ~Turtle() {} ... }
代码检查工具提示需遵循Rule of 3,于是我添加了:
Turtle() = default; Turtle(const Turtle& x) = default; Turtle& operator=(const Turtle& x) = default;
之后工具仍提示需添加移动构造函数和移动赋值运算符,我又补充了:
Turtle(Turtle&& x) = default; Turtle& operator=(Turtle&& x) = default;
这符合Rule of 5的要求,但每个继承该接口的类都需要重复添加虚析构及这5个默认特殊成员函数。我有两个疑问:
- 我的实现方式是否正确?
- 是否必须编写如此多的样板代码?
解答
1. 实现方式的正确性
你的实现是语法正确的,但从设计角度看,对于纯接口类(仅包含虚函数/纯虚函数、无非静态成员变量的类),这些显式声明的默认特殊成员函数其实没有实际执行逻辑——因为接口类本身无法实例化,所有拷贝、移动操作都是针对派生类的。
需要重点注意:虚析构的声明是必须的,这是为了保证通过基类指针/引用销毁派生类对象时,能正确调用派生类的析构函数,避免内存泄漏。而其他特殊成员函数的默认声明,更多是满足代码检查工具的规则要求,本身不会引入错误。
2. 避免样板代码的方案
不需要重复编写这些代码,有两种常用方案:
方案1:封装通用接口基类
创建一个通用的接口基类,把虚析构和所有默认特殊成员函数都封装进去,让所有业务接口类继承它:
// 通用接口基类,封装重复的样板代码 class BaseInterface { protected: // 保护构造函数,禁止直接实例化基类 BaseInterface() = default; virtual ~BaseInterface() = default; // 默认拷贝/移动操作 BaseInterface(const BaseInterface&) = default; BaseInterface& operator=(const BaseInterface&) = default; BaseInterface(BaseInterface&&) = default; BaseInterface& operator=(BaseInterface&&) = default; }; // 业务接口类只需专注于声明接口方法 class Turtle : public BaseInterface { public: virtual void forward(int distance) = 0; virtual void turn(int degrees) = 0; // ...其他接口方法 };
这样所有派生的接口类都不需要重复编写那些样板代码,只需要定义自身的接口方法即可。
方案2:调整代码检查规则(若允许)
如果你的代码检查工具支持自定义规则,可以针对纯接口类放宽Rule of 3/5的要求——因为纯接口类无法实例化,其特殊成员函数的声明更多是形式上的,不会影响实际运行逻辑。
内容的提问来源于stack exchange,提问作者fatdragon
相关产品推荐
相关产品推荐

