C++中防止继承陷阱的设计技术

Design Techniques to Defend Against the Pitfalls of Inheritance in C++

本文关键字:技术 陷阱 继承 C++      更新时间:2023-10-16

摘要

在更改父类中成员函数的签名时,我依靠编译器指向代码中需要更新的每个位置,但编译器未能在子类中指出该函数的重写实例,导致程序出现逻辑错误。我想重新实现这些类,这样在进行此类更改时可以更多地依赖编译器。

通过示例的详细信息

我有以下课程:

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的子类(,调用的bar((方法是b:bar((

在更改了A:bar((的类型签名后,比如说A:bar(some_parameter(,我的代码看起来是这样的:

void A:foo(){ ... bar(param); ... }
void A:bar(param) { ... }
void B:bar(){ ... }

现在,当我调用b->foo((时,当然会调用A:bar(param(。我本以为编译器会发现这样的情况,但现在我意识到它做不到。

我将如何实现类A&B以避免此类错误。

我本以为编译器会发现这样的情况,但现在我意识到了

事实上,它可以这样做。你可以在B::bar的声明中使用override,如果没有合适的基类函数可以重写,编译器就会出错。

在c++03中检测这个问题的方法是在接口中执行纯虚拟方法,因为它还没有override说明符(这是因为c++11标准(。如果您更改纯虚拟方法的符号,那么它的所有子类也必须更改它,否则它们将无法编译。

不要依赖于具体的类别。取决于接口。你会做得更好。

你的设计会变成这样:

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的符号,那么它的所有子类也必须更改它。