【问题标题】:Getting Link Errors with virtual functions when linking between two projects在两个项目之间链接时使用虚函数获取链接错误
【发布时间】: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


【解决方案1】:

但ConsolApp2 无法编译并引发三个链接错误。

错了,ConsolApp2.cpp 确实编译。问题不是编译,而是linking

在你的项目中,你应该编译

  • FooDerived.cpp
  • FooImplement.cpp
  • ImplementMain.cpp

如果不是,请将缺少的模块添加到您的项目中。

在这种情况下,FooDerived.cpp 似乎没有被编译或不是 Visual Studio 项目的一部分。

【讨论】:

    猜你喜欢
    • 2013-02-03
    • 2020-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多