摘要(正文的废话太多,不想浪费时间可以不看)
VC中使用类模板,如果类的成员函数声明和定义分别放在.h和.cpp文件中,连接的时候会报错如下:
1.obj : error LNK2001: unresolved external symbol "public: void __thiscall node<int>::display(void)" (?display@?$node@H@@QAEXXZ)
Debug/1.exe : fatal error LNK1120: 1 unresolved externals
Error executing link.exe.
1.exe - 2 error(s), 0 warning(s)
解决办法:
方法一:不要分成两个文件,把成员函数的声明和定义都放在.h文件里面
方法二:如果你确定的知道这个模板只会被用成那些类型,可以在.cpp文件的末尾加上template class 类名<可能的类型>;
比如写了一个节点类node,只可能用在int和double类型,那么在.cpp文件最后加上如下语句:
template class node<int>;
template class node<double>;
如果还有其他类型,每种类型必须添加一句
推荐使用第一种方法.
=======================以下为正文======================
为了VC++本身的一个不足,我居然浪费了2天的时间!
背景:
最近突然兴趣高涨,啃起了数据结构,本来作为编程的一门基本功,数据结构这门课应该早就学过了,可惜咱不是正宗的计算机系出身,本来的专业跟计算机那差的可不是一般的远.对计算机的学习纯粹是兴趣使然,所以学习的方向也就是随心所欲,没有系统的学习,也没有人指点.还好现在的网络实在是发达,各种XX教程多如牛毛上的细胞,所以目前的水平自认为还是可以的(呃,可以糊弄那些没学过编程的).最近终于对数据结构提起兴趣,那就赶快学起来,这块不学始终是不行的,于是看起了北大的张铭老师的视频教程,个人评价是讲的还行(如果不是太困的话不会睡着),不过因为课时的限制,有些地方讲的太简略.
起因:
教程已经看到了图,根据多年自学编程的经验,光看教程是绝对不可能学会的,编程这东西,肯定要在实践中才能真正学到东西,光听别人讲或者光看书,那太简单了,等到自己编起来才会发现问题多的很.
经过:
于是开始练习,第一个目标当然是最简单的单链表了(MS这个都算不上是数据结构了).经过仔细的考虑,最终决定使用C++来实现,"类"是一个好东西,不用浪费了.IDE选择了VC6,我还是比较喜欢VC的,调试功能比较完善.
新建工程,添加一个node类,VC还自动生成了两个文件node.h和node.cpp,构造和析构函数也都写好了,还有node.h前面的防止重入也写好了,的确不错.
因为以前还没真正编过C++的东西,大大小小的错误一堆,不过还是在我超强的DEBUG能力下,一一解决,最后程序如下:
// node.h: interface for the node class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_NODE_H__AA536975_5993_483D_BA04_BEBC765ADF87__INCLUDED_)
#define AFX_NODE_H__AA536975_5993_483D_BA04_BEBC765ADF87__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <iostream.h>
template<typename T>
class node
{
private:
T _value;
node *_next;
public:
node(T value,node* next)
{
_value=value;
_next=next;
}
node(T value)
{
_value=value;
_next=NULL;
}
node()
{
_value=0;
_next=NULL;
}
void display(void);
virtual ~node(){}
};
#endif // !defined(AFX_NODE_H__AA536975_5993_483D_BA04_BEBC765ADF87__INCLUDED_)
// node.cpp: implementation of the node class.
//
//////////////////////////////////////////////////////////////////////
#include "node.h"
template<class T>
void node<T>::display()
{
cout<<"Value="<<_value<<" Next="<<_next<<" This="<<this<<endl;
}
然后写了一个main函数测试,内容太简单就不写了.测试结果link的时候提示2个error
1.obj : error LNK2001: unresolved external symbol "public: void __thiscall node<int>::display(void)" (?display@?$node@H@@QAEXXZ)
Debug/1.exe : fatal error LNK1120: 1 unresolved externals
Error executing link.exe.
1.exe - 2 error(s), 0 warning(s)
这次我就不行了,怎么弄都解决不了这个错误.那只能开始找资料,百度上搜了半天,又找了C++ Primer第3版和第5版,找了关于template的介绍,甚至还找了stl的源码,找了候捷老师的<STL源码剖析>.最终的结论是,这样写没错..........
最后没办法,还是靠百度,搜索template unresolved external symbol,终于明白了错误所在
原来是VC本身的原因,对于这种使用类模板,又把成员函数的声明和定义分别放在.h和.cpp文件中的情况,VC没办法智能的找到模板的定义,导致他认为两个文件中的声明和定义不一致.
解决的办法有两种,一是全部定义的放在.h文件中,二是在.cpp文件最后加上template class 类名<可能的类型>;
比如我们的node类模板,可能会被用成int和double,那么就要写两句
template class node<int>;
template class node<double>;
如果还有更多的可能,就要每种可能再写一行.
结果:
第二种解决方法显然不能使用,简单变量类型还好说,要是以后有自定义的类,那还要修改这个地方,而且到时候还不一定他能认识.
那只能用第一种了,把所有的定义写在.h文件里面.其实stl里面也是这么干的.
后记:
问题终于解决,两天来的郁闷也终于过去了,万里长征已经踏出了第一步,后面的路还很长很长..........
最后BS一下VC...........