继承管理:final 和 delete
MQL5 允许您对类和结构体的继承施加一些限制。
关键字final
通过在类名后添加 final 关键字,开发者可以禁用该类的继承。例如 (FinalDelete.mq5):
class Base
|
编译器将抛出错误“无法从 'Derived' 继承,因为它已被声明为 'final'”。
遗憾的是,对于使用此类限制的好处和场景,目前尚无共识。该关键字让类的使用者知道,由于某种原因,类的作者不建议将其作为基类(例如,其当前实现为草案,以后会发生很大变化,这可能会导致潜在的遗留项目停止编译)。
有些人试图鼓励以这种方式设计程序,即使用对象(组合)来代替继承。过度使用继承反而会增加类的耦合性(即相互影响),因为所有的子类都可以在某种程度上改变父类的数据或方法(特别是通过重定义虚函数)。因此,程序工作逻辑的复杂性和出现不可预见副作用的可能性都会增加。
使用 final 的另一个好处是编译器可以进行代码优化:对于 "final" 类型的指针,它可以用静态调度替换虚函数的动态调度。
关键字delete
可以在方法头中指定 delete 关键字,使其在当前类及其后代类中不可访问。父类的虚方法不能以这种方式删除(这会违反类的“契约”,即继承者将不再“是 (is a)”同一类型的代表)。
class Base
|
尝试调用它将导致编译错误。
我们在 对象类型转换 章节中看到了类似的错误,因为编译器具有一定的智慧,可以在特定条件下“移除”方法。
建议将编译器提供隐式实现的以下方法标记为已删除:
- 默认构造函数: Class(void) = delete;
- 拷贝构造函数:Class(const Class &object) = delete;
- 拷贝/赋值运算符:void operator=(const Class &object) = delete。
如果您需要其中任何一个,则必须显式定义。否则,一般认为放弃隐式实现是一种良好习惯。问题是,隐式实现非常简单,并且可能会引发难以定位的问题,尤其是在强制转换对象类型时。