3

私がこのようなものを持っているとき:

class A
{
  virtual void rat();
};

class B : public A
{
  virtual void rat() { ; } //implemented!
};

int main(int argc, char **argv)
{
  A *a = new B;
  delete a;
}

リンカーエラーが発生します:

ベースラットを純粋な仮想にしない限り。

しかし、私がこれを持っているとき:

class A
{
  public:
  void rat();
};

int main(int argc, char **argv)
{
  A a;
}

これは正常にコンパイルされ、main()でrat関数を明示的に呼び出そうとしない限り、未定義の参照リンクエラーは発生しませんa.rat();。実装されていない基本クラスの仮想関数のルールは何ですか?ただし、最初の失敗したコードスニペットのように派生クラスに実装されていますか?

4

5 に答える 5

5

両方のクラスが仮想関数を定義する場合、C++コンパイラは両方のクラスとのvtablesを構築する必要があります。のvtableをビルドするには、コンパイラが必要です-参照元の場所です。ABAA::rat()

Aに仮想関数がない場合、どこからも参照できA::ratないため、コンパイルエラーは発生しません。

ご存知のとおり、A::rat純粋仮想を作成してこのエラーを修正し、vtableに必要な値を提供できます(この場合、値はゼロです)。

于 2012-05-04T19:48:22.853 に答える
4

すべての非純粋仮想関数を実装する必要があります。

class A 
{ 
   public: void rat(); 
};

int main(int argc, char **argv) 
{ 
  A a; 
}

上記のコードはまったく別のシナリオです。純粋でない仮想関数を呼び出さない状況では、クラス定義で宣言されているにもかかわらず、まったく呼び出さないため、コンパイラー/リンカーエラーも発生しません。

以下のコードでは、コンパイラはに名前が付けられたメンバー関数があるかどうかをチェックするだけrat()ですA

A a;
a.rat();   // Compiler passes. But linker bombs.

これで、リンカーエラーが発生するはずです。

于 2012-05-04T19:46:25.343 に答える
2

は純粋な仮想でA::rat()ないため、実装が必要です。

于 2012-05-04T19:47:37.060 に答える
2

標準の法律用語はODRで使用されます。ODRで使用される関数を定義する必要があります。定義しないとエラーになります。

関数をODR使用としてマークするためのルールは非常に複雑で、基本的には関数が何らかの方法で使用されていることを意味します。2番目の例では、関数は使用されていないため、不要です。

特別な注意点が1つあります。virtual関数(純粋でない限り)は常にODR使用と見なされます。

于 2012-05-04T19:50:26.130 に答える
2

C++標準では実装が必要なためです。C++03§10.3/8から:

クラスで宣言された仮想関数は、そのクラスで定義されるか、純粋(10.4)として宣言されるか、またはその両方である必要があります。ただし、診断は必要ありません(3.2)。

したがって、純粋であると宣言するか(= 0右括弧の後に接尾辞を付けて)、その実装を定義する必要があります。

非仮想の場合に関数を呼び出さなくてもエラーが発生しない理由については、C++03§3.2/2-3(強調鉱山)を参照してください。

2)式は、積分定数式が必要な場合(5.19を参照)、演算子のオペランド(5.3.3)、または演算子のオペランドであり、式がの左辺値を指定しない場合を除いて、潜在的に評価されます。多態的なクラスタイプ(5.2.8)。オブジェクトまたはオーバーロードされていない関数は、その名前が評価される可能性のある式に含まれている場合に使用されます。純粋でない場合は、仮想メンバー関数が使用されます。[...]sizeoftypeid

3)すべてのプログラムには、そのプログラムで使用されるすべての非インライン関数またはオブジェクトの定義が1つだけ含まれている必要があります。診断は必要ありません。定義は、プログラムに明示的に表示することも、標準またはユーザー定義のライブラリに含めることも、(適切な場合は)暗黙的に定義することもできます(12.1、12.4、および12.8を参照)。インライン関数は、それが使用されるすべての変換単位で定義されるものとします。

したがって、非仮想の場合、それが使用されない場合、定義は必要ありません。ただし、純粋でない仮想の場合、コードで明示的に参照されていなくても、標準で使用されていると見なされるため、その定義が必要です。

関連項目仮想メンバー関数は、純粋でない場合に使用されますか?

于 2012-05-04T20:02:26.653 に答える