虚拟方法何时应该是纯方法

When should a virtual method be pure?

本文关键字:方法 何时应 虚拟      更新时间:2023-10-16

我找到了一些我正在处理的代码,并且想知道最好的设计实现是什么。

如果基类将方法定义为虚拟方法,但也实现了一个空主体,因此不需要派生类来实现主体,那么它不应该成为纯体吗?

virtual void AMethod1() {}                 // 1
virtual void AMethod2() {assert(false);}   // 2
virtual void AMethod3() = 0;               // 3
  1. 当前代码。
  2. Idea1:提醒用户此派生对象尚未实现此方法体。
  3. Idea2:强制派生类实现主体,无论是否为空。

您,值得信赖的了不起的 SO 人员,怎么看?


编辑1:发布(并阅读答案(后,我意识到断言是不好的!

virtual void AMethod3() = {throw (ENotImplemented)};               // 4

这有点取决于你的编码风格有多"纯粹"。有些人认为你应该始终只定义一个只用纯虚函数的接口,并从中派生出所有具体的类。

其他人则更务实,并且相信如果有一个良好的默认实现,则可以将其添加到基类(选项 1(。

第二个选项似乎最没有用,因为它将检测延迟到运行时。大多数程序员宁愿选择选项 3 中的编译错误。

像往常一样,C++支持多种范式,您可以选择自己喜欢的一种。

如果派生类必须实现此方法,则应使用选项 3。如果在派生类中的实现是可选的,请使用选项 1。完全避免选项 2。

如果基类将方法定义为虚拟方法,但也实现了一个空主体,因此不需要派生类实现主体,那么它不应该被设为纯体吗?

这取决于是否要强制派生类重写该方法。如果你这样做,那么使用纯virtual;正是针对该要求的语言支持。如果以后有或可能在某个时候是 amethod 的默认实现,则使用纯virtual方法和实现:

class Foo {
    virtual void amethod() = 0;
};
void Foo::amethod() {
    // whatever
}

该函数现在仍然是纯virtual因此无法实例化Foo类,但任何派生类都将继承实现,其方法可以将其调用为 Foo::amethod

使方法纯虚拟比使用断言进行默认实现更直观。如果在大多数情况下什么都不做是默认实现,则当前代码会更好。当然,如果你想使用多态性,它应该保持虚拟。

  • virtual void AMethod1() = 0;:当你的基类没有要提供的实现并且应该实现这种行为时,纯虚拟是最好的。(这是您问题中的选项 3(

  • virtual void AMethod1() {}:当您的基类没有要提供的实现并且可以实现此行为时,具有空实现的虚拟是最好的。(这是您问题中的选项 1(

  • virtual void AMethod1() { assert(false); } :在我看来,必须避免带有assert(false)的虚拟。我看不出它有任何有效的用途。这背后的基本原理是,上述两个选项涵盖了所有用例:行为可能应该实现,因此定义总是失败的可调用方法没有用。编译器可以通过阻止此调用来为您处理此问题,因此此选项会将此检查推迟到运行时,从而引入风险。(这是您问题中的选项 2(

我见过很多这样的例子,你需要实例化类,所以您将virtual与空主体一起使用:

virtual void AMethod1() {}                 // 1

如果要强制派生类重写,请使用此选项此函数,您不需要默认值:

virtual void AMethod3() = 0;               // 3

所以这真的取决于你想做什么。

如果我们不这样做,我们应该使用纯虚函数想要实例化一个类,但让它充当基类对于从它派生的所有类。

一件重要的事情关于纯虚函数需要注意的是,这些必须在所有派生类中重写函数否则,编译将标记错误。

简单例如,

class alpha     {
     public:virtual void show()=0; //pure virtual function
    };
class beta : public alpha {
     public:void show()   //overriding
        {
         cout<<"OOP in C++";
        }
    };
void main() {
     alpha *p;
     beta b;
     p=&b;
     p->show();
   }

如果基类将方法定义为虚拟方法,但实现一个空 主体,因此不需要派生类实现 一个身体,难道不应该被做成纯净吗?

这取决于您的设计。如果你的方法是纯虚拟的,你正在向派生类开发人员发送一条消息,说">你必须在这里放置一些实际代码,以便你的类工作"。另一方面,如果你的方法是虚拟的,有一个空的主体,则消息是">你可以在这里放置一些代码,但这取决于你的实际需求"。

virtual void AMethod1() {}                 // 1
virtual void AMethod2() {assert(false);}   // 2
virtual void AMethod3() = 0;               // 3

我肯定更喜欢选项 3 而不是 2,如果派生类没有实现虚拟方法,它会产生编译错误而不是运行时错误。

由于您需要virtual机制;以下是我的简短回答:

(1( virtual void AMethod1() {}

要求:

- Allow creating objects of base class
- Base `virtual` method is use.

(2) virtual void AMethod2() {assert(false);}

要求:

- Allow creating objects of base class
- Base method is not used
- Force derived classes to implement the method (hard way, because it happens at runtime).

(3) virtual void AMethod3() = 0;

要求:

- Don't allow base class object creation
- Force derived classes to implement the method at compile time

没有简单的规则:

如果对某些派生类有意义,请使用 1(空实现(在调用函数时不执行任何操作。

如果派生类不实现功能。

在函数的前提条件为另一个虚函数 Hare 返回 true,该函数具有默认实现返回 false(或类似的东西(。基本上,如果接口的一部分是可选的。 (但通常,它是在这种情况下,最好派生一个接口;实现扩展接口派生自它,客户端希望使用它 dynamic_cast到扩展接口。

根据经验(但你的编程风格可能不同(,1 似乎至少在 90% 的情况下适用,我认为在 20 多年的C++中,我用过 3 一次,或者两次。