2016-10-18 42 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 
} 

當學嘗試婷編譯,我得到了所有的虛方法如下錯誤:

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

只要我宣佈在「DerivedClass.h」,錯誤消失,因爲編譯器這些方法現在已經知道的方法。

但是,我很困惑。爲什麼有必要重新聲明DerivedClass.h中的純虛函數?當我#include DerivedClass.h時,它會自動包含BaseClass.h,因此我假定我的DerivedClass.cpp應該完全知道這些方法。我做錯了什麼嗎?

+0

每個派生類必須覆蓋其基類的虛函數。簡單的規則。附註:當你有一個不帶參數的函數時,你不需要放棄void。 – DeiDei

+1

@DeiDei簡單,但不完全正確 – krzaq

+0

正確,這就是我在DerivedClass.cpp中所做的。但是,爲什麼有必要重新聲明DerivedClass.h中的函數?編譯器是否應該期待方法定義? – Izzo

回答

6

這不起作用。您需要聲明您要定義的方法,無論它們是否覆蓋虛擬方法。

這不僅僅是對語言的不合理要求。如果沒有這一點,你將無法定義部分虛擬類,即你可以有BaseSubtype擁有的method1()共同實現,但需要從它派生實現method2()method3()

0

類當你在派生類中聲明的方法,你要說到編譯器:

我想覆蓋這種方法在這個類

所以,如果你沒有在派生類中聲明的方法,你說:

我不想重寫此方法;派生類的實現是一樣的一個基類

在你的情況下,基類聲明它們爲純虛擬的,所以在這種情況下,它可以解釋:

我不t要在此類中實現此方法

如果您嘗試定義方法但未聲明它,那麼您自相矛盾。編譯器檢測到(爲了保護您免於疏忽)。

-1

爲什麼必須在基類中派生重寫的虛方法,這是一個非直觀的原因,因爲C++允許將類的不同部分放入不同的文件中,放入不同的翻譯單元中。

對於其他一些語言(我正在研究Java的方向),一個類必須放在一個文件中。這在C++中是不正確的。對於一個類在一個翻譯單元中聲明其某些方法以及在另一個翻譯單元中聲明的其他方法完全合法,這些方法可能完全位於某個不同目錄中的文件中。

每個這樣的文件被分別編譯和單獨編譯。編譯一個翻譯時,C++編譯器不知道任何其他翻譯單元,任何其他文件,可能包含同一類的其他部分。

現在我們假設您可以從類聲明中忽略重寫的虛擬方法。這就產生了一個直接的問題:編譯類的構造函數時,編譯器必須知道該類是否覆蓋了任何超類中的任何虛方法,以便正確組裝正在構造的類的虛表分派。沒有明確的聲明,編譯器無法知道其他翻譯單元是否可能定義重寫的虛擬方法。

這就是爲什麼重寫的虛擬方法必須顯式包含在類聲明中的原因。總之:因爲C++ formally specifies phase 9, the linkage phase,在早期階段進行實際編譯,必須明確聲明重寫的方法。

+0

你在回答中混淆了聲明和定義。 – rubenvb

0

你應該重寫所有的基類純虛函數,以便能夠實例化派生類。

  • 您無法從派生類定義基類成員函數。

在您的示例中,您正在嘗試定義method1和method2以及method3,它們不是DerivedClass的成員!你必須在派生類中自己聲明它們。編譯器不會爲你做。

所以你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 
相關問題