什么时候虚拟方法应该是纯粹的?

时间:2011-07-27 11:03:55

标签: c++ methods derived-class pure-virtual

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

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

virtual void AMethod1() {}                 // 1
virtual void AMethod2() {assert(false);}   // 2
virtual void AMethod3() = 0;               // 3
  1. 当前代码。
  2. Idea1:警告用户此派生对象尚未实现此方法体。
  3. Idea2:强制派生类实现一个正文,无论是否为空。
  4. 你是什么,值得信赖的神奇SO人,你会怎么想?


    Edit1:发帖(并阅读答案)后,我意识到断言很糟糕!

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

10 个答案:

答案 0 :(得分:9)

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

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

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

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

答案 1 :(得分:6)

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

答案 2 :(得分:3)

  

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

这取决于您是否希望强制派生类来覆盖该方法。如果你这样做,那么使用纯virtual;它完全符合该要求的语言支持。如果稍后有或可能是amethod的默认实现,则使用纯virtual方法实现:

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

void Foo::amethod() {
    // whatever
}

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

答案 3 :(得分:2)

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

答案 4 :(得分:2)

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

virtual void AMethod1() {}                 // 1

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

virtual void AMethod3() = 0;               // 3

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

答案 5 :(得分:2)

  • virtual void AMethod1() = 0;:如果您的基类没有实现提供 AND ,当此行为应该<时,纯虚拟是最好的/ strong>实施。 (这是你问题中的选项3)

  • virtual void AMethod1() {}:如果您的基类没有实现提供 AND 此行为 MAY 实施。 (这是你问题中的选项1)

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

答案 6 :(得分:1)

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

重要的是 关于纯虚函数的注意就是这些 必须在所有派生类中重写函数 否则编译会标记出错误。

很简单,

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();
   }

答案 7 :(得分:1)

因为你需要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

答案 8 :(得分:1)

  

如果基类将方法定义为虚拟,但实现为空   身体也是如此,因此不需要派生类来实现   一个身体,不应该变得纯净吗?

这取决于您的设计。如果您的方法是纯虚拟的,那么您将向派生类开发人员发送一条消息,告知“您必须在此处放置一些实际代码,以使您的课程正常工作”。另一方面,如果您的方法是虚拟的空体,则消息是“您可能在此处放置一些代码,但这取决于您的实际需求”。

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

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

答案 9 :(得分:0)

没有简单的规则:

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

如果派生类没有实现,则使用3 功能

在极少数情况下使用2,其中函数的前提条件是 另一个虚函数hare返回true,该函数有一个 默认实现返回false(或沿着这些行的东西)。 基本上,如果界面的一部分是可选的。 (但通常,它是 在这种情况下更好地导出界面;实现的类 扩展接口派生自它,客户想要使用它 dynamic_cast扩展接口。)

根据经验(但你的编程风格可能不同),1似乎至少有90%的时间适用,而且我认为在二十多年的C ++中,我曾经使用过3次,或者两次。