【问题标题】:LNK2019 linking error in C++ [duplicate]C ++中的LNK2019链接错误[重复]
【发布时间】:2012-09-03 07:05:17
【问题描述】:

可能重复:
C++ template, linking error

我有两个链接错误,我不知道代码有什么问题以及如何修复它们:

main.obj:-1: error: LNK2019: unresolved external symbol "public: __thiscall A::A(void)" (??0?$A@VB@@@@QAE@XZ) 在函数 "public: __thiscall B::B(void)" (??0B@@QAE@XZ) 中引用)

main.obj:-1: error: LNK2019: unresolved external symbol "public: void __thiscall A::exec(void (__thiscall B::*)(void))" (?exec@?$A@VB@@@@QAEXP8B@@AEXXZ@Z) 在函数“public: void __thiscall B::run(void)" (?run@B@@QAEXXZ)

稍微解释一下代码: 这个类必须执行派生类的函数。函数 exec 从派生类中调用,并带有派生类参数中的函数。这个函数的签名是void function();

//header.h

#ifndef HEADER_H
#define HEADER_H

template <class T>
class A
{
public:
    typedef void (T::*ExtFunc)();

    A();
    void funcA();
    void exec(ExtFunc func);
};

#endif // HEADER_H

//header.cpp

#include "header.h"

template<typename T>
A<T>::A() { }

template<typename T>
void A<T>::funcA()
{
    cout << "testA\n";
}

template<typename T>
void A<T>::exec(ExtFunc func)
{
    (T().*func)();
}

main.cpp 中,我从 A 类派生一个类,并将派生类作为模板参数传递。然后我通过run()函数执行函数exec。 //main.cpp

#include <iostream>
#include "header.h"
using namespace std;

class B : public A<B>
{
public:
    B() { }

    void run()
    {
        exec(&B::funcB);
    }

    void funcB()
    {
        cout << "testB\n";
    }
};

int main()
{
    B ob;
    ob.run();

    return 0;
}

谁能告诉我这是怎么回事?...

【问题讨论】:

    标签: c++ class templates linker external


    【解决方案1】:

    当您使用模板时,通常不能将实现放在 .cpp 文件中 - 您必须将整个类放在标题中。因此将所有代码从 header.cpp 移动到 .h。

    您可以通过在 .cpp 文件中进行显式实例化来解决此问题 - 为特定类型实例化模板。但这要求您提前知道哪些类型需要实例化,并且会阻止您添加新的实例化。唯一的好处是减少了编译时间。

    【讨论】:

    • 另一种可能的hack在头文件中包含源文件
    • 感谢您的回答。我在网上做了一些搜索,看看之前的代码有什么问题,我找到了你刚才说的。但是在 cplusplus.com 论坛上,我发现一个人说这可能的。问题是我没有从他的评论中弄清楚如何做到这一点。 cplusplus.com/forum/general/14162/#msg69074这是guestgulkan (2668)的第一条评论
    • @JohnSmith,这就是我认真回答的原因:)。如果你在 .cpp 文件中显式地实例化模板,它实际上会创建类型,因此它对链接器可用。但这样做的主要原因是为了减少编译时间,所以在大多数情况下,您应该简单地将实现保留在头文件中。
    • 如果我真的想把编译时间放在第二位以便更好地组织事情,难道没有任何可能吗?我见过这样声明的模板类(标题/源),它们工作得很好。如果他们不报告任何错误,我不知道他们有什么特别之处。
    • @JohnSmith,正如 Hindol 指出的那样,您也可以将它们拆分,只要您将“源”文件视为标题。事实上,在库这样做的情况下,它们专门为这些文件使用不同的扩展名,以表明它们不是 .cpp 文件。
    猜你喜欢
    • 1970-01-01
    • 2015-06-28
    • 1970-01-01
    • 1970-01-01
    • 2023-03-30
    • 1970-01-01
    • 1970-01-01
    • 2014-08-11
    相关资源
    最近更新 更多