抵御 C++ 继承陷阱的设计技巧
Design Techniques to Defend Against the Pitfalls of Inheritance in C++
总结
我依靠编译器指向代码中我需要更新的每个位置,同时更改 parent class 中的成员函数的签名,但编译器无法指向在 child class 中输出该函数的重写实例,导致我的程序出现逻辑错误。我想 re-implement classes 以便我可以在进行此类更改时更多地依赖编译器。
示例详细信息
我有以下 classes:
class A
{
public:
void foo();
virtual void bar();
}
class B: public A
{
public:
void bar();
}
这是实现:
void A:foo(){ ... bar(); ... }
void A:bar(){ ... }
void B:bar(){ ... }
请注意,当我调用 b->foo() 时(其中 b 的类型为 B*,B 是 A 的子 class),调用的 bar() 方法是 B:bar()
在更改 A:bar() 的 type-signature 之后,说 A:bar(some_parameter),我的代码看起来像这样:
void A:foo(){ ... bar(param); ... }
void A:bar(param) { ... }
void B:bar(){ ... }
现在,当我调用 b->foo() 时,当然会调用 A:bar(param)。我希望这种情况会被编译器捕获,但我现在意识到它不能。
我将如何实施 classes A 和 B 以避免此 class 的错误。
I expected such a case to be caught by the compiler, but I realize now
that it cannot do so.
其实是可以的。您可以在 B::bar
的声明中使用 override
,如果没有合适的基础 class 函数供其覆盖,编译器将出错。
在还没有 override
说明符(自 c++11 标准起)的 c++03 中检测此问题的方法是在接口中执行纯虚方法。如果你改变了一个纯虚方法的标志,它的所有子类也必须改变它,否则它们将无法编译。
不依赖具体类。依赖接口。你会做更好的设计。
你的设计会变成这样:
class IA
{
public:
void foo() { ... bar(); ...}
virtual void bar() = 0;
virtual ~IA() {}
};
class A : public IA
{
public:
void bar() {...}
};
class B : public IA
{
public:
void bar() {...}
};
现在,如果你改变界面中bar的符号,它的所有sub类也必须改变。
总结
我依靠编译器指向代码中我需要更新的每个位置,同时更改 parent class 中的成员函数的签名,但编译器无法指向在 child class 中输出该函数的重写实例,导致我的程序出现逻辑错误。我想 re-implement classes 以便我可以在进行此类更改时更多地依赖编译器。
示例详细信息
我有以下 classes:
class A
{
public:
void foo();
virtual void bar();
}
class B: public A
{
public:
void bar();
}
这是实现:
void A:foo(){ ... bar(); ... }
void A:bar(){ ... }
void B:bar(){ ... }
请注意,当我调用 b->foo() 时(其中 b 的类型为 B*,B 是 A 的子 class),调用的 bar() 方法是 B:bar()
在更改 A:bar() 的 type-signature 之后,说 A:bar(some_parameter),我的代码看起来像这样:
void A:foo(){ ... bar(param); ... }
void A:bar(param) { ... }
void B:bar(){ ... }
现在,当我调用 b->foo() 时,当然会调用 A:bar(param)。我希望这种情况会被编译器捕获,但我现在意识到它不能。
我将如何实施 classes A 和 B 以避免此 class 的错误。
I expected such a case to be caught by the compiler, but I realize now that it cannot do so.
其实是可以的。您可以在 B::bar
的声明中使用 override
,如果没有合适的基础 class 函数供其覆盖,编译器将出错。
在还没有 override
说明符(自 c++11 标准起)的 c++03 中检测此问题的方法是在接口中执行纯虚方法。如果你改变了一个纯虚方法的标志,它的所有子类也必须改变它,否则它们将无法编译。
不依赖具体类。依赖接口。你会做更好的设计。
你的设计会变成这样:
class IA
{
public:
void foo() { ... bar(); ...}
virtual void bar() = 0;
virtual ~IA() {}
};
class A : public IA
{
public:
void bar() {...}
};
class B : public IA
{
public:
void bar() {...}
};
现在,如果你改变界面中bar的符号,它的所有sub类也必须改变。