Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C+中防止继承陷阱的设计技术+;_C++_Oop_Inheritance_Refactoring - Fatal编程技术网

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

C++ C+中防止继承陷阱的设计技术+;,c++,oop,inheritance,refactoring,C++,Oop,Inheritance,Refactoring,摘要 在更改父类中成员函数的签名时,我依靠编译器指向代码中需要更新的每个位置,但编译器未能指出子类中该函数的重写实例,导致程序中出现逻辑错误。我想重新实现这些类,以便在进行此类更改时可以更多地依赖编译器 通过示例了解详细信息 我有以下课程: class A { public: void foo(); virtual void bar(); } class B: public A { public: void bar(); } 这就是实现: void A:foo(){

摘要

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

通过示例了解详细信息

我有以下课程:

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(某个_参数),我的代码如下所示:

void A:foo(){ ... bar(param); ... }
void A:bar(param) { ... }
void B:bar(){ ... }
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() {...}
};
现在,当我调用b->foo()时,当然会调用A:bar(param)。我原以为编译器会捕捉到这种情况,但现在我意识到它不能

我将如何实现类A和B以避免此类的错误

我原以为编译器会发现这样的情况,但现在我意识到了 它不能这样做

事实上,它可以做到。您可以对
B::bar
的声明使用
override
,如果没有合适的基类函数供编译器重写,编译器将出错

我原以为编译器会发现这样的情况,但现在我意识到了 它不能这样做


事实上,它可以做到。您可以在
B::bar
的声明上使用
override
,如果没有合适的基类函数供编译器重写,编译器将出错。

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

不要依赖于具体的类。依赖于接口。你会做更好的设计

您的设计将更改为以下内容:

void A:foo(){ ... bar(param); ... }
void A:bar(param) { ... }
void B:bar(){ ... }
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的符号,那么它的所有子类也必须更改它。

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

不要依赖于具体的类。依赖于接口。你会做更好的设计

您的设计将更改为以下内容:

void A:foo(){ ... bar(param); ... }
void A:bar(param) { ... }
void B:bar(){ ... }
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符号,那么它的所有子类也必须更改它。

Hmm。。。如果功能是虚拟的,那就行了。我同意。我最近修复了一个困扰我的错误,它显式地添加了
override
属性,并且编译器对其进行了标记。@DrewDormann:嗯,问题文本与其自己的代码不匹配。根据这个问题,作者有“一个被覆盖的函数实例”。。。是的,那一定是虚拟的。。。如果功能是虚拟的,那就行了。我同意。我最近修复了一个困扰我的错误,它显式地添加了
override
属性,并且编译器对其进行了标记。@DrewDormann:嗯,问题文本与其自己的代码不匹配。根据这个问题,作者有“一个被覆盖的函数实例”。。。是的,那一定是
virtual
@Jarod42不,在我处理的遗留代码中,bar()不是virtual。因此,这表明您的第一个假设是错误的,
A::bar()
被调用,而不是
B::bar()
。感谢您指出这一点。我的错误:A:bar()声明为虚拟,但我认为它不是纯虚拟的。我会修改原件的example@Jarod42不,在我处理的遗留代码中,bar()不是虚拟的。因此,这表明您的第一个假设是错误的,
A::bar()
被调用,而不是
B::bar()
。感谢您指出这一点。我的错误:A:bar()声明为虚拟,但我认为它不是纯虚拟的。我将修正原来的例子,这表明C++和C++ 11之间有区别,除了C++现在是14,它包含了<代码>覆盖> <代码>。在C++03中,我提出了一种不同的解决方案来在编译时检测这种问题。我做这件事是因为他没有指定在C++ 11或14中做这件事。这表明C++和C++ 11之间有区别——除了C++现在是14,它包含了<代码>覆盖> <代码>。在C++03中,我提出了一种不同的解决方案来在编译时检测这种问题。我这样做是因为他没有指定在C++11或14中这样做。