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()を実装せずにコンパイルします。

the = 0; 関数宣言の最後には、基本的に、すべてのBigDuckがクワクワクするが、派生した各アヒルによって実装される必要があると書かれています。=0を削除することによって; HugeDuckにquackを実装しない限り、BigDuckquackが呼び出されます。

編集:=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 は別の抽象クラスである可能性があり、基本クラスの ReallyBigDuck に到達するまで quack を実装したくない場合があります。

于 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 に答える