none
关于在模板函数和析构函数使用中出现LNK2019的求助 RRS feed

  • 问题

  • 亲爱的各位大师:
         很抱歉再次打扰,但我仔细的查阅了msdn中关于LNK2019的描述,以及搜索过互联网,经过尝试并没有找到解决方案。
         以下为重现该问题的简略版代码,请指出问题所在。(分三个文件)

    //error LNK2019: 无法解析的外部符号 "public: __thiscall LinkedList<int>::~LinkedList<int>(void)" (??1?$LinkedList@H@@QAE@XZ),该符号在函数 _main 中被引用 main.obj test


    //LinkedList.h
    template<typename T>
    class LinkedList
    {
    public:
     LinkedList():begin(0),listcounter(0){}
     ~LinkedList();
    private:
     int*begin;
     int listcounter;
    };
    //////////////////////////////////////////////////////////////////////////
    //LinkedList.cpp
    #include "LinkedList.h"
    template <typename T>
     LinkedList<T>::~LinkedList()
     {
      clearall();
     }
    //////////////////////////////////////////////////////////////////////////
    //test.cpp
    #define CONSTRUCTING

    #include<iostream>
    using namespace std;

    #include "LinkedList.h"

    int main()
    {
    #ifdef CONSTRUCTING
     LinkedList<int> test1;
     //LinkedList<int> test2(test1);
    #endif
    }

    2009年11月24日 13:26

答案

  • 谢谢施斑竹回复,该函数确实忘记定义了(抽取的代码忘记了检查),但在我定义后仍然出现错误:
    错误 1 error LNK2019: 无法解析的外部符号 "public: __thiscall LinkedList<int>::~LinkedList<int>(void)" (??1?$LinkedList@H@@QAE@XZ),该符号在函数 _main 中被引用 main.obj test

    谢谢SplendourG斑竹回复,使用的版本是VS.NET2008SP1,标准应用应该是最新的,将定义写入类体内是为了应用初始化列表,而遵照您的建议,将函数实现移动到cpp中后,按如下代码:
    //LinkedList.cpp
    #include "LinkedList.h"
    template <typename T>
     LinkedList<T>::~LinkedList()
     {
      clearall();
     }
     
     template<typename T>
     void LinkedList<T>::clearall()
     {
     }
    template<typename T>
     LinkedList<T>::LinkedList()
    {
     begin=0;
     listcounter=0;
    }
    //////////////////////////////////////////////////////////////
    //LinkedList.h
    template<typename T>
    class LinkedList
    {
    public:
     LinkedList();
     ~LinkedList();
     void clearall();
    private:
     int*begin;
     int listcounter;
    };

    错误列表中多出了一条LNK2019:
    错误 1 error LNK2019: 无法解析的外部符号 "public: __thiscall LinkedList<int>::~LinkedList<int>(void)" (??1?$LinkedList@H@@QAE@XZ),该符号在函数 _main 中被引用 main.obj test
    错误 2 error LNK2019: 无法解析的外部符号 "public: __thiscall LinkedList<int>::LinkedList<int>(void)" (??0?$LinkedList@H@@QAE@XZ),该符号在函数 _main 中被引用 main.obj test

    请各位大虾斟酌。
    是不能写到cpp中,因为连接过程需要看到实现。
    //LinkedList.h
    template<typename T>
    class LinkedList
    {
    public:
     LinkedList():begin(0),listcounter(0){}
     ~LinkedList()
    {
      clearall();
     }


    private:
     int*begin;
     int listcounter;
    };
    //////////////////////////////////////////////////////////////////////////
    //LinkedList.cpp
    #include "LinkedList.h"


     //////////////////////////////////////////////////////////////////////////

    麻烦把正确答案设为解答。
    • 已标记为答案 LinZhe Li 2009年11月27日 5:47
    2009年11月26日 1:03
    版主
  • 因为模板并不是运行期多态,它需要在编译期,通过具现的方式产生相应类型的类或者函数。但此时如果无法找到定义的话就无法完成具现的过程。
    你需要把类型相关的函数都定义到头文件中。
    模板并不是面向对象的标准特性。就像异常处理机制一样,他只是C++新添加的特性。对外模块的接口不要使用模板。你可以选择使用运行时多态。


    麻烦把正确答案设为解答。
    • 已标记为答案 LinZhe Li 2009年11月27日 5:47
    2009年11月27日 1:29
    版主
  • 谢谢诸位的回答与关注,该问题已经在C++Primer中文版(第4版)中得到圆满解答。。
    请参见其第542-544页。
    • 已标记为答案 LinZhe Li 2009年11月27日 5:47
    2009年11月27日 5:47

全部回复

  • 模板类需要具现,你不能把函数的实现写到CPP文件中。
    //LinkedList.h
    template<typename T>
    class LinkedList
    {
    public:
     LinkedList():begin(0),listcounter(0){}
     ~LinkedList()
    {
      clearall();
     }
    private:
     int*begin;
     int listcounter;
    };
    C++0x可以将模板函数的实现写到类之外了。


    麻烦把正确答案设为解答。
    2009年11月25日 1:25
    版主
  • clearall();定义了没有?
    欢迎光临我的个人网站:http://www.joyvc.cn,本网站提供[IM即时通信|棋牌游戏|网游开发|UI编程|网络通讯|组件开发|图像多媒体|数据库]方面的VC/C++/C技术文章、源代码和教程资料
    2009年11月25日 5:13
    版主
  • 谢谢施斑竹回复,该函数确实忘记定义了(抽取的代码忘记了检查),但在我定义后仍然出现错误:
    错误 1 error LNK2019: 无法解析的外部符号 "public: __thiscall LinkedList<int>::~LinkedList<int>(void)" (??1?$LinkedList@H@@QAE@XZ),该符号在函数 _main 中被引用 main.obj test

    谢谢SplendourG斑竹回复,使用的版本是VS.NET2008SP1,标准应用应该是最新的,将定义写入类体内是为了应用初始化列表,而遵照您的建议,将函数实现移动到cpp中后,按如下代码:
    //LinkedList.cpp
    #include "LinkedList.h"
    template <typename T>
     LinkedList<T>::~LinkedList()
     {
      clearall();
     }
     
     template<typename T>
     void LinkedList<T>::clearall()
     {
     }
    template<typename T>
     LinkedList<T>::LinkedList()
    {
     begin=0;
     listcounter=0;
    }
    //////////////////////////////////////////////////////////////
    //LinkedList.h
    template<typename T>
    class LinkedList
    {
    public:
     LinkedList();
     ~LinkedList();
     void clearall();
    private:
     int*begin;
     int listcounter;
    };

    错误列表中多出了一条LNK2019:
    错误 1 error LNK2019: 无法解析的外部符号 "public: __thiscall LinkedList<int>::~LinkedList<int>(void)" (??1?$LinkedList@H@@QAE@XZ),该符号在函数 _main 中被引用 main.obj test
    错误 2 error LNK2019: 无法解析的外部符号 "public: __thiscall LinkedList<int>::LinkedList<int>(void)" (??0?$LinkedList@H@@QAE@XZ),该符号在函数 _main 中被引用 main.obj test

    请各位大虾斟酌。
    2009年11月25日 7:35
  • 谢谢施斑竹回复,该函数确实忘记定义了(抽取的代码忘记了检查),但在我定义后仍然出现错误:
    错误 1 error LNK2019: 无法解析的外部符号 "public: __thiscall LinkedList<int>::~LinkedList<int>(void)" (??1?$LinkedList@H@@QAE@XZ),该符号在函数 _main 中被引用 main.obj test

    谢谢SplendourG斑竹回复,使用的版本是VS.NET2008SP1,标准应用应该是最新的,将定义写入类体内是为了应用初始化列表,而遵照您的建议,将函数实现移动到cpp中后,按如下代码:
    //LinkedList.cpp
    #include "LinkedList.h"
    template <typename T>
     LinkedList<T>::~LinkedList()
     {
      clearall();
     }
     
     template<typename T>
     void LinkedList<T>::clearall()
     {
     }
    template<typename T>
     LinkedList<T>::LinkedList()
    {
     begin=0;
     listcounter=0;
    }
    //////////////////////////////////////////////////////////////
    //LinkedList.h
    template<typename T>
    class LinkedList
    {
    public:
     LinkedList();
     ~LinkedList();
     void clearall();
    private:
     int*begin;
     int listcounter;
    };

    错误列表中多出了一条LNK2019:
    错误 1 error LNK2019: 无法解析的外部符号 "public: __thiscall LinkedList<int>::~LinkedList<int>(void)" (??1?$LinkedList@H@@QAE@XZ),该符号在函数 _main 中被引用 main.obj test
    错误 2 error LNK2019: 无法解析的外部符号 "public: __thiscall LinkedList<int>::LinkedList<int>(void)" (??0?$LinkedList@H@@QAE@XZ),该符号在函数 _main 中被引用 main.obj test

    请各位大虾斟酌。
    是不能写到cpp中,因为连接过程需要看到实现。
    //LinkedList.h
    template<typename T>
    class LinkedList
    {
    public:
     LinkedList():begin(0),listcounter(0){}
     ~LinkedList()
    {
      clearall();
     }


    private:
     int*begin;
     int listcounter;
    };
    //////////////////////////////////////////////////////////////////////////
    //LinkedList.cpp
    #include "LinkedList.h"


     //////////////////////////////////////////////////////////////////////////

    麻烦把正确答案设为解答。
    • 已标记为答案 LinZhe Li 2009年11月27日 5:47
    2009年11月26日 1:03
    版主
  • 谢谢SplendourG 兄的解答。

    恩,将定义放到头文件中后就没有问题了。。。
    但还请各位仁兄解释,为什么一定要将定义放在头文件中呢?这不符合封装的想法不是?将源代码放在头文件中似乎也会在商业开发中出现产权的矛盾。
    恩,而且#include预处理指令好像也类似于将头文件的内容复制到源文件中,与将代码写在头文件中似乎也没有什么区别?

    。。。

    还有,请问这个是所有的函数定义都要放在头文件中还是仅仅是构造函数、析构函数已经他们调用的函数的定义要放在头文件中?

    经过试验,clearall()的定义也要放在头文件中,否则出现如下错误:

    错误 1 error LNK2019: 无法解析的外部符号 "public: void __thiscall LinkedList<int>::clearall(void)" (?clearall@?$LinkedList@H@@QAEXXZ),该符号在函数 "public: __thiscall LinkedList<int>::~LinkedList<int>(void)" (??1?$LinkedList@H@@QAE@XZ) 中被引用 main.obj test
    
    2009年11月26日 4:15
  • 因为模板并不是运行期多态,它需要在编译期,通过具现的方式产生相应类型的类或者函数。但此时如果无法找到定义的话就无法完成具现的过程。
    你需要把类型相关的函数都定义到头文件中。
    模板并不是面向对象的标准特性。就像异常处理机制一样,他只是C++新添加的特性。对外模块的接口不要使用模板。你可以选择使用运行时多态。


    麻烦把正确答案设为解答。
    • 已标记为答案 LinZhe Li 2009年11月27日 5:47
    2009年11月27日 1:29
    版主
  • 谢谢SplendourG 兄的解答。

    但请原谅我的无知,请问类型相关函数具体指的是哪些函数?
    而对外模块指的又是什么?
    对于运行时多态,可能的话请SplendourG 兄举出一个例子可否?
    2009年11月27日 2:56
  • 还想请问兄台一个问题。。。
    在工业化的开发中,是如何处理这个问题的?编译时排除头文件可行吗?

    2009年11月27日 3:47
  • 谢谢诸位的回答与关注,该问题已经在C++Primer中文版(第4版)中得到圆满解答。。
    请参见其第542-544页。
    • 已标记为答案 LinZhe Li 2009年11月27日 5:47
    2009年11月27日 5:47
  • 呵呵,这是个最有利的回答
    编程是一个耗体力的活,但是所失去的,可以在一个程序顺利运行时,补回来
    2011年10月29日 13:29