在另一个项目中包含继承类时抽象类的链接器错误
Posted
技术标签:
【中文标题】在另一个项目中包含继承类时抽象类的链接器错误【英文标题】:Linker Error with abstract class when including inherited class in another project 【发布时间】:2017-03-19 13:35:31 【问题描述】:如果我有一个抽象类
像这样:
#pragma once
#include <string>
class BaseObject
public:
virtual std::string to_string() = 0;
;
有些类扩展了这个类。
#pragma once
#include "baseobject.h"
class Point : BaseObject
public:
Point()
~Point()
Point(float _x, float _y) : x(_x), y(_y)
std::string to_string();
float x, y;
;
在同一个项目中,我可以在派生类的 cpp 文件中实现 to_string
的函数,但是当我想在同一个解决方案中的另一个项目中使用这个类时,我得到一个链接器错误
error LNK2001: unresolved external symbol "public: virtual class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl Point::to_string(void)" (?to_string@Point@@UEAA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ)
1>path\to\CircleHT_Test.exe : fatal error LNK1120: 1 unresolved externals
一旦我将实现移到头文件中,一切都很好。为什么是这样?我应该总是在派生类的头文件中实现纯虚函数吗?
【问题讨论】:
当您构建“另一个项目”时,您使用定义了Point::to_string
的源文件(或其生成的目标文件)构建?
@Someprogrammerdude 使用 VS 我在项目设置中将 point.h 和 point.cpp 所在的路径添加到 Additional Include Directories
- 我认为这也会包括 Point::to_string
所在的 .cpp已定义。
【参考方案1】:
在同一个项目中,我可以实现以下功能
to_string
在扩展类的 cpp 文件中,但是当我想 在同一个解决方案的另一个项目中使用这个类我得到一个链接器 错误。
Point::to_string
的实现源码在某个实现文件里,大概叫point.cpp
。该文件包含在项目的源文件列表中。因此,当您构建项目时,它会被编译成一个 point.obj
文件,其中包含函数的二进制代码。反过来,该文件最终被链接器用来生成可执行程序。
当您构建不同的项目时,point.cpp
不在源文件列表中。您在某处包含point.h
的事实无关紧要。将类分成*.cpp
和*.h
文件只是一个非常常见的约定。如果您只包含 *.h
文件并且不确保将相应的 *.cpp
文件编译为 *.obj
文件,那么结果正是您在这里遇到的:没有创建 point.obj
,因此,链接器正确地抱怨缺少定义。
最简洁的解决方案是将第一个项目或第一个项目的一部分转换为一个库项目,该项目被构建到一个*.lib
文件中。然后应该将该*.lib
文件添加到每个需要它的应用程序项目的链接器依赖项中。
一旦我将实现移到头文件中,一切都很好。这是为什么呢?
因为在这种情况下,函数的实现是内联的,并且包含头文件的其他项目中的每个*.cpp
文件都会得到它。
最后,请注意这个答案在某种程度上特定于 Visual Studio / Visual C++,尽管构建过程的基本思想通常与每个工具集相同。
【讨论】:
要创建这样的库项目我可以只创建一个新项目 -> win32 控制台应用程序 -> 应用程序类型:dll 吗? @Philipp:如果你想要一个 *.dll,是的,但我会说你最好使用 *.lib 类型。 我现在创建了一个库项目,这很有效 - 感谢您的帮助。以上是关于在另一个项目中包含继承类时抽象类的链接器错误的主要内容,如果未能解决你的问题,请参考以下文章
如何在基类的函数上使用装饰器并在继承基类时让装饰器在该函数上工作
为 iOS 构建 OCUnit 应用程序测试目标时出现链接器错误