29
#include <iostream>
using namespace std;

class Duck {
public:
        virtual void quack() = 0;
};

class BigDuck : public Duck {
public:
  //  void quack();   (uncommenting will make it compile)

};

void BigDuck::quack(){ cout << "BigDuckDuck::Quack\n"; }

int main() {
        BigDuck b;
        Duck *d = &b;
        d->quack();

}

上面的代码无法编译。但是,当我在子类中声明虚函数时,它编译得很好。

如果编译器已经具有子类将覆盖的函数的签名,那么为什么需要重新声明?

有什么见解吗?

4

7 回答 7

24

需要重新声明,因为:

  • 标准是这样说的。
  • 通过不爬上层次结构来检查此类函数是否存在,它使编译器的工作更容易。
  • 您可能希望在层次结构中将其声明为较低。
  • 为了实例化类,编译器必须知道这个对象是具体的。
于 2010-06-02T13:22:59.213 回答
12

如果你改变:

virtual void quack() = 0;

virtual void quack();

无需在 HugeDuck 中实现 quack() 即可编译。

= 0; 在函数声明的末尾基本上是说所有 BigDucks 都会嘎嘎,但它必须由每个派生的鸭子实现。通过删除 = 0; 除非您在 HugeDuck 中实现 quack,否则 BigDuck quack 将被调用。

编辑:澄清 = 0; 是说派生类将具有函数的定义。在您的示例中,它期望 HugeDuck 定义 quack(),但是正如您所评论的那样,它没有。

作为旁注,由于所有鸭子都可以嘎嘎叫,也许我们看不到的原始 Duck 类应该实现 quack() 吗?

于 2010-06-02T13:29:25.190 回答
7

因为 C++ 将“声明”与“多态性”分开:任何函数都需要编译器的声明,无论它是否是虚拟的。

您的示例还远远不够,它存在“抽象类”问题:无法实例化 BigDuck,因为它的接口中没有 quack 的实现。

概括问题,我们可以声明基函数不是纯虚函数:

class Duck { public: virtual void quack(){} };

class BigDuck : public Duck {}; 

// WRONG: undeclared method definition
void BigDuck::quack(){ cout << "QUACK!"; }

在这里,编译器会抱怨它有一个BigDuck::quack未声明的符号。这与抽象类或任何东西无关。

(注:gcc 说 error: no 'void BigDuck::q()' member function declared in class 'BigDuck' :)

于 2010-06-02T13:27:32.587 回答
2

基类中的定义Quack()是“抽象的”——它没有实现。这告诉编译器你的派生类必须实现它。不这样做是编译错误。

于 2010-06-02T13:18:42.787 回答
2

BigDuck 可能是另一个抽象类,您可能不想实现 quack,直到您到达基类ReallyBigDuck。

于 2010-06-02T13:19:03.867 回答
2

在您提供实现之前,从包含的类继承的所有类 Pure Virtual Function都是抽象的——它们不能被实例化。为了提供这样的实现,您必须在类中声明该函数。

于 2010-06-02T13:20:45.427 回答
1

在每个类中声明方法将告诉编译器该类为该方法提供不同的实现。

此外,如果您想BigDuck在堆栈上创建对象,那么编译器应该如何知道quack().

BigDuck aDuck;
aDuck.quack();
于 2010-06-02T13:21:23.550 回答