重载默认构造函数导致错误

问题描述:

多年来,我一直在开发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

它看起来像实体没有链接到玩家。确保输出显示它编译和他们都添加到您的项目

你还需要在你的基类来定义一个虚析构函数

编辑:

它没有先编译,我的错。在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