如果我有一个抽象类
像这样:#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
一旦我将实现移动到头文件,这一切都很好。为什么是这样?我是否应该始终在派生类的标题中实现纯虚函数?
答案 0 :(得分:1)
在同一个项目中,我可以使用函数实现
to_string
在扩展类的cpp文件中,但是在我想要的时候 在同一个解决方案的另一个项目中使用此类我得到一个链接器 错误。
Point::to_string
实现的源代码位于某个实现文件中,可能称为point.cpp
。该文件包含在项目的源文件列表中。在构建项目时,它会被编译为point.obj
文件,其中包含该函数的二进制代码。反过来,该文件最终被链接器用于生成可执行程序。
构建其他项目时,point.cpp
不在源文件列表中。您在某处包含point.h
这一事实无关紧要。将类分为*.cpp
和*.h
文件只是一种非常常见的约定。如果您只包含*.h
文件并且不确保将相应的*.cpp
文件编译为*.obj
文件,则结果正是您在此处遇到的结果:否{{ 1}}已创建,因此,链接器正确地抱怨缺少定义。
最干净的解决方案是将第一个项目或第一个项目的一部分转换为库项目,该项目将内置到point.obj
文件中。然后应该将*.lib
文件添加到需要它的每个应用程序项目的链接器依赖项中。
一旦我将实现移动到头文件,它一切都很好。这是为什么?
因为在这种情况下,函数的实现是内联的,并且包含头文件的另一个项目中的每个*.lib
文件都会获得它。
最后,请注意,这个答案有点特定于Visual Studio / Visual C ++,尽管构建过程的基本思想通常与每个工具集相同。