【发布时间】:2014-06-07 05:58:15
【问题描述】:
我在一个名为 ConsolApp1 的项目中创建了一个基类和派生类,其中基类有几个虚拟方法和一个虚拟析构函数。这些方法都设置为纯虚拟方法,然后在派生类中定义并使用 override 关键字覆盖。此外,派生类和基类都包装在命名空间中。当我创建一个名为ConsolApp2 的新项目时,它与ConsolApp1 位于相同的解决方案中,它实现了派生类的对象 链接错误出现在任何声明为虚拟的方法或析构函数中。为了允许ConsolApp2 包含派生类及其所在的命名空间,我必须将路径添加到头文件的位置。我很确定我这样做是正确的,因为当我尝试包含它时会显示头文件。提前感谢您的帮助。
这是我遇到的问题的一些伪代码。我能够毫无错误地编译ConsolApp1,但ConsolApp2 没有构建并引发三个链接错误,两个用于虚拟方法,一个用于虚拟析构函数。使用VS2012进行编译。错误是:
错误 LNK2001: 无法解析的外部符号“public: virtual int const __thiscall FooSpace::FooDerived::GetSomething(void)const” (?GetSomething@FooDerived@FooSpace@@UBE?BHXZ)
错误 LNK2001: 无法解析的外部符号 "public: virtual void __thiscall FooSpace::FooDerived::SetSomething(int)" (?SetSomething@FooDerived@FooSpace@@UAEXH@Z)
错误 LNK2019:在函数“public: virtual void * __thiscall FooSpace: :FooDerived::`标量删除析构函数'(unsigned int)" (??_GFooDerived@FooSpace@@UAEPAXI@Z)
ConsolApp1:
FooBase.h
namespace FooSpace
{
class FooBase
{
public:
FooBase(){}
virtual ~FooBase() {}
virtual const int GetSomething() const = 0;
virtual void SetSomething(int f) = 0;
};
}
FooDerived.h
#include "FooBase.h"
namespace FooSpace
{
class FooDerived : FooBase
{
public:
FooDerived() : FooBase(){}
~FooDerived() override;
const int GetSomething() const override;
void SetSomething(int f) override;
};
}
FooDerived.cpp
#include "FooDerived.h"
FooSpace::FooDerived::~FooDerived()
{
//destruct an object of FooDerived
}
const int FooSpace::FooDerived::GetSomething() const
{
int ret = 0;
return ret;
}
void FooSpace::FooDerived::SetSomething(int f)
{
// Set some private variable equal to f
}
FooMain.cpp -> 包含以确保缺少 main() 不会出错
#include "FooDerived.h"
using namespace FooSpace;
int main()
{
FooDerived derivedObject;
return 0;
}
ConsolApp2:
FooImplement.h
#include <FooDerived.h>
#include <vector>
using namespace std;
using namespace FooSpace;
class FooImpliment
{
private:
vector<FooDerived> fooVector;
public:
FooImpliment(void);
~FooImpliment(void);
void SetFooVector(vector<FooDerived> newVector);
};
FooImplement.cpp
#include "FooImpliment.h"
FooImpliment::FooImpliment(void)
{
}
FooImpliment::~FooImpliment(void)
{
}
void FooImpliment::SetFooVector(vector<FooDerived> newVector)
{
fooVector = newVector;
}
ImplementMain.cpp -> 包含以消除缺少 main() 的错误
int main()
{
return 0;
}
【问题讨论】:
-
您没有提到您实际为 ConsoleApp2 编译了哪些模块,或者您的项目使用哪些模块来构建 ConsoleApp2。告诉我们头文件在哪里并不能解决链接器错误——它所做的只是让编译器满意,但编译器不是链接器。很可能,您未能编译依赖模块,和/或您的 ConsoleApp2 项目设置未列出链接器正在查找的模块。
-
我使用VS2012编译,但是你能解释一下你所说的模块是什么意思吗?我认为通过将ConsolApp1的路径包含在ConsolApp2中,我应该能够包含ConsolApp1的头文件而不会出现链接错误。那么有没有我忘记在 ConsolApp2 中修改的属性设置?
-
您的回答表明您不了解编译/链接过程。当您创建应用程序时,项目必须列出所有的 .cpp 和其他需要构建的模块文件(以及任何第三方库),因此链接器将为每个找到相关的目标代码被调用的函数。链接器不会神奇地在您的目录中搜索来自另一个项目的先前编译。每个项目都是独立的。
-
到目前为止,在我所做的所有其他项目中,他们需要来自不同项目的头文件,我没有遇到任何问题,只需包含头文件所在的路径即可链接它们
-
当你编译一个模块(例如.cpp 文件)时,你会创建一个目标文件(通常带有.obj 扩展名)。当需要链接时,链接器将获取给定的 .obj 文件列表,并搜索您调用的函数。如果找不到该函数,则会给出错误。同样,链接器(至少是 Microsoft 链接器)不够智能,无法确定您在其他项目中编译的模块,因此无法使用该模块。
标签: c++ inheritance virtual linker-errors