2016-10-18 7 views
4

私は単純なC++プログラムに取り組んでおり、私が得ていたコンパイラエラーを理解するのが難しいです。この問題は、基底クラスから派生クラスを作成しようとしていたために発生しました。私は同じ構造で私のコードを掲載しましたが、名前を変更しました。継承されたクラスから仮想関数を再宣言する必要があるのはなぜですか?

BaseClass.h

#ifndef BASECLASS_H 
#define BASECLASS_H 

class BaseClass { 

    public: 
     BaseClass(void); 

     virtual int method1(void) = 0; 
     virtual int method2(void) = 0; 
     virtual float method3(void) = 0; 

}; 

#endif // BASECLASS_H 

DerivedClass.h

#ifndef DERIVEDCLASS_H 
#define DERIVEDCLASS_H 

#include "DerivedClass.h" 

class DerivedClass: public BaseClass 
{ 

    public: 
     DerivedClass(void);  
}; 

#endif // DERIVEDCLASS_H 

DerivedClass.cpp

#include "DerivedClass.h" 

DerivedClass::DerivedClass(void) 
{ 
} 

int DerivedClass::method1(void) 
{ 
    // TODO 
} 

int DerivedClass::method2(void) 
{ 
    // TODO 
} 

float DerivedClass::method3(void) 
{ 
    // TODO 
} 

attempティンはこれをコンパイルするために、私はすべての仮想メソッドの次のエラーを取得する:コンパイラは今の認識しているので、

no 'int DerivedClass::methodX()' member function declared in class 'DerivedClass' 

はできるだけ早く私は、「DerivedClass.h」でこれらのメソッドを宣言すると、エラーが離れて行きますメソッド。

しかし、私は混乱しています。 DerivedClass.hの純粋仮想関数を再宣言する必要があるのはなぜですか?私がDerivedClass.hを#includeすると、自動的にBaseClass.hがインクルードされるので、DerivedClass.cppはメソッドを完全に認識しているはずです。間違っていることをしていますか?

+0

。単純なルール。サイドノート:パラメータを必要としない関数がある場合は、voidを入れる必要はありません。 – DeiDei

+1

@DeiDeiシンプルですが、正確には正しくありません – krzaq

+0

正しいです。それはDerivedClass.cppでやろうとしています。しかし、なぜDerivedClass.hの関数を再宣言する必要がありますか?コンパイラはすでにメソッド定義を期待していますか? – Izzo

答えて

6

この方法では動作しません。仮想メソッドをオーバーライドしているかどうかにかかわらず、定義するメソッドを宣言する必要があります。

これは、言語の不合理な要件ではありません。これがなければ、あなたは、つまり、あなたがmethod1()の一般的な実装を持っていますが、派生クラスでメソッドを宣言する場合method2()

0

method3()を実装するために、そこから派生したクラスを必要とBaseSubtypeを持つことができ、部分的に仮想クラスを定義することができないであろうコンパイラに言う:

私が欲しいこのクラスでは、この方法オーバーライド

ですから、派生クラスでメソッドを宣言しない場合は、あなたは言う:

私はこのメソッドをオーバーライドしたくありません。派生クラスの実装では、あなたのケースでは

基本クラスのものと同じである。この場合には、それは言い換えることができるので、ベースクラスは、純粋仮想としてそれらを宣言します。

私はドン」このクラスでこのメソッドを実装したくない場合

メソッドを定義して宣言しないと、宣言しません。コンパイラはそれを検出します(自分の過失からあなたを守るため)。

-1

オーバーライドされた仮想メソッドが基本クラスで派生しなければならない非常に非直感的な理由は、C++がクラスの異なる部分を異なるファイル、異なる翻訳単位に配置できるという事実に由来します。

他の言語(私はJavaの方向を見ています)では、1つのクラスを1つのファイルに配置する必要があります。これはC++では当てはまりません。あるクラスがある翻訳単位で宣言されたメソッドと別の翻訳単位で宣言された他のメソッドを別のディレクトリのファイルにまとめておくことは、クラスにとって完全に合法です。

このような各ファイルは個別に個別にコンパイルされます。 1つの翻訳をコンパイルするとき、C++コンパイラは、他の翻訳単位、つまり同じクラスの他の部分を含む可能性のある他のファイルを認識していません。

ここで、クラス宣言からオーバーライドされた仮想メソッドを省略することが許可されているとします。クラスのコンストラクタをコンパイルするときに、構築されているクラスの仮想テーブルディスパッチを正しくアセンブルするために、クラスがスーパークラスのいずれかの仮想メソッドをオーバーライドするかどうかをコンパイラが知る必要があります。明示的な宣言がなければ、コンパイラは、他の変換単位がオーバーライドされた仮想メソッドを定義しているかどうかを知る方法がありません。

そのため、オーバーライドされた仮想メソッドを明示的にクラスの宣言に含める必要があります。結論として:C++ formally specifies phase 9, the linkage phaseは、実際のコンパイルを前の段階で実行しているため、オーバーライドされたメソッドを明示的に宣言する必要があります。

+0

あなたはあなたの答えにかなり多くの宣言と定義を混ぜています。 – rubenvb

0

派生クラスをインスタンス化できるように、すべての基本クラスの純粋仮想関数をオーバーライドする必要があります。

  • 派生クラスから基本クラスメンバー関数を定義することはできません。

あなたの例では、DerivedClassのメンバーではないmethod1とmethod2とmethod3を定義しようとしています。派生クラスで自分で宣言する必要があります。コンパイラはあなたのためにそれをしません。

ので、あなたのDerivedclass.hは、次のようになります。各派生クラスは、その基底クラスの仮想関数をオーバーライドする必要があります

#ifndef DERIVEDCLASS_H 
#define DERIVEDCLASS_H 

#include "BaseClass.h" 

class DerivedClass: public BaseClass 
{ 

    public: 
     DerivedClass(void); 

     virtual int method1(void); // not pure function 
     virtual int method2(void); 
     virtual float method3(void); 
}; 

#endif // DERIVEDCLASS_H 
関連する問題