2014-11-02 107 views
0

多年來,我一直在開發C#和Java(在許多其他語言之間),而現在我只是在C++中弄溼了自己的腳。我把自己埋在了繼承和類的資源之中,但我似乎無法弄清楚如何擺脫這個令人討厭的錯誤。重載默認構造函數導致錯誤

我的代碼:

Entity.h

#ifndef ENTITY_H 
#define ENTITY_H 

#include <iostream> 

class Entity 
{ 
public: 
    std::string m_name; 

    void update(float delta); 
    Entity(); 

private: 
    virtual void step(float delta); 
}; 

#endif 

Entity.cpp

#include "Entity.h" 

Entity::Entity() 
{ 
    m_name = "Generic Entity"; 
} 

void Entity::update(float delta) 
{ 
    step(delta); 
} 

void Entity::step(float delta) {} 

Player.h

#ifndef PLAYER_H 
#define PLAYER_H 

#include "Entity.h" 

class Player : public Entity 
{ 
public: 
    Player(); 

private: 
    virtual void step(float delta); 

    virtual void draw() const; 
}; 

#endif 

Player.cpp

#include "Player.h" 

Player::Player() 
{ 
    m_name = "Player"; 
} 

void Player::step(float delta) {} 

void Player::draw() const {} 

Main.cpp

int main() 
{ 
    return 0; 
} 

正如你所看到的,我不這樣做與類的任何信息,但我發現這些錯誤:

Error 3 error LNK1120: 1 unresolved externals C:\[...]\Debug\ConsoleApplication1.exe ConsoleApplication11 
Error 2 error LNK2019: unresolved external symbol "public: __thiscall Entity::Entity(void)" ([email protected]@[email protected]) referenced in function "public: __thiscall Player::Player(void)" ([email protected]@[email protected]) C:\[...]\ConsoleApplication1\Player.obj ConsoleApplication1 

更新:代碼奇蹟般地工作,當我註釋掉Player.cpp中的以下代碼時:

/*Player::Player() 
{ 
    m_name = "Player"; 
}*/ 
+0

如何編譯它?並且私有虛擬方法沒有意義 – 2014-11-02 03:30:28

+0

看起來您並未鏈接「Entity.cpp」的目標代碼,很可能是因爲您沒有編譯該文件。還要注意,要使用'std :: string',你應該包含'',而不是''。儘管代碼可能與某些編譯器一起編譯,但它可能無法與其他編譯器一起編譯。 – 2014-11-02 03:30:34

+0

@BryanChen Microsoft Visual Studio Express 2013 for Windows Desktop – Entity 2014-11-02 03:30:58

回答

1

它看起來像實體沒有鏈接到玩家。確保輸出顯示它編譯和他們都添加到您的項目

你還需要在你的基類來定義一個虛析構函數

編輯:

它沒有先編譯,我的錯。在C/C++中,程序創建分兩步進行。首先,編譯器爲您的cpp文件創建obj文件,例如Entity.obj,Player.obj等等。然後鏈接器會將所有內容捆綁在一起。

在Player.cpp中,你說你在某個時候會有一個名爲Entity的類,因此編譯器會在.h文件中找到該類的定義。 Player.cpp然後被轉換成Player.obj中的可執行代碼,但它不包含Entity.obj可執行代碼。編譯步驟起作用。

然後鏈接器將嘗試解析Player.obj並找到編譯器所說的Entity.obj將存在。如果沒有,那麼你會得到「未定義的引用」錯誤,因爲找到的定義與實際的可執行文件不匹配。

虛擬析構函數是強制性的。 C++的繼承方式是使用虛擬表。對於每個具有繼承的類,將使用虛擬條目創建一個虛擬表(vtable)。當執行鏈接步驟時,鏈接器將使用實際功能填充虛擬表。當代碼執行時,它會檢查該類的vtable,然後執行該函數。這使您可以「覆蓋」基本方法,或者如果沒有添加新內容,則使用基本方法。虛擬析構函數在該表中爲析構函數創建條目。如果虛擬析構函數沒有條目,那麼子類將不會有條目,並且將無法正確銷燬基類,這會導致未定義的行爲

+0

以下是構建順序:'Player.cpp,main.cpp,Entity.h,Entity.cpp'。爲什麼我需要虛擬析構函數? – Entity 2014-11-02 03:37:00

+0

Entity.h不應該被建立。它不包含可執行代碼 – Eric 2014-11-02 03:48:53

+2

我現在感覺很蠢,那是整個問題。 Entity.h被標記爲由visual studio編譯。你的解釋也很有幫助,謝謝:) – Entity 2014-11-02 03:52:24