类的成员函数声明和定义不放在同一个文件中的问题

时间:2021-08-05 13:06:26
首先是一个节点结构体类型;

/*
*TList.h;节点结构体模板,实现给定数据类型节点在链表中的插入、删除、查找操作。
*/

#ifndef TLIST_H
#define TLIST_H

template < typename T >
struct Node
{
T value ;
Node *next ;
} ;


#endif


我定义了一个MyTList.h头文件,里面包含一个类的定义,
和成员函数的声明;


/*
*MyTList.h,自定义节点类型链表;添加删除查找节点;
*/
#ifndef MYTLIST_H
#define MYTLIST_H
#include "TList.h"
#include <iostream>


template < typename T >
class MyTList
{
private:
Node < T > *head ;
size_t size ;
public:
MyTList() ;
bool insert( T aNode ) ;
bool erase( T aNode ) ;
size_t findaNode( T aNode ) ;
void print() ;
~MyTList() ;
} ;
#endif


然后我又建立的一个MyTList.cpp文件,

#include "MyTList.h"
#include "TList.h"
#include <iostream>

template < typename T >
MyTList < T >::MyTList()
{
head = NULL ;
size = 0 ;
}

template < typename T >
MyTList < T >::~MyTList()
{
Node < T > *temp ;
Node < T > *p = head ;
while ( p )
{
temp = p ;
p = p->next ;
delete temp ;
}
}

template < typename T >
bool MyTList < T >::insert( T aNode )
{
Node < T > *aNewNode = new Node < T > ;
if ( aNewNode )
{
aNewNode->value = aNode ;
aNewNode->next = head ;
head = aNewNode ;
++size ;
return true ;
}
else
{
return false ;
}
}

template < typename T >
bool MyTList < T >::erase( T aNode )
{
size_t tmp_size = size ;
Node < T > *temp = head ;
Node < T > *p = head ;
while ( temp )
{
if ( temp->value == aNode )
{
if ( temp == head) 
{
head = temp->next ;
}
p->next = temp->next ;
--size ;
delete temp ;
temp = NULL ;
if ( !temp )
{
break ;
}
}
else
{
p = temp ;
temp = temp->next ;
}
}

if ( tmp_size == size )
{
return false ;
}
else
{
return true ;
}
}

template < typename T >
size_t MyTList < T >::findaNode( T aNode )
{
size_t tmp_size = 1 ;
Node < T > *temp = head ;
while ( temp )
{
if ( temp->value == aNode )
{
break ;
}
else
{
temp = temp->next ;
++tmp_size ;
}
}
if ( temp )
{
return tmp_size ;
}
else
{
return 0 ;
}
}

template < typename T >
void MyTList < T >::print()
{
Node < T > *p = head ;
while ( p )
{
std::cout << p->value << "  " ;
p = p->next ;
}
std::cout << std::endl ;
}



主函数:


/*
*MyTList_main.cpp;多类型节点链表,测试主函数;
*/


#include "MyTList.h"
#include <iostream>

int main()
{
MyTList < int > MyintList ;
for ( int i = 0 ; i < 10 ; ++i )
{
MyintList.insert( i ) ;
}
MyintList.print() ;
MyTList < double > MydoubleList ;
for ( double i = 1.1 ; i < 11 ; ++i )
{
MydoubleList.insert( i ) ;
}
MydoubleList.print() ;

std::cout << "9在链表中的位置是:" 
 << MyintList.findaNode( 9 )
 << std::endl ;
std::cout << "9.9在链表中的位置是:" 
 << MydoubleList.findaNode( 9.9 )
 << std::endl ;

if ( MyintList.erase( 9 ) )
{
std::cout << "9在链表中删除!" << std::endl ;
}
if ( MydoubleList.erase( 9.9 ) )
{
std::cout << "9.9在链表中删除!" << std::endl ;
}
MyintList.print() ;
MydoubleList.print() ;

MyTList < char * > MystringList ;
MystringList.insert( "!" ) ;
MystringList.insert( "list" ) ;
MystringList.insert( "string" ) ;
MystringList.insert( "a" ) ;
MystringList.insert( "is" ) ;
MystringList.insert( "This " ) ;
MystringList.print() ;

std::cout << "\"is\"在链表中的位置为:"
 << MystringList.findaNode( "is" ) 
 << std::endl ;

if ( MystringList.erase( "!" ) )
{
std::cout << "\"!\" is delete !" << std::endl ;
}
std::cout << "\"is\"在链表中的位置为:"
 << MystringList.findaNode( "!!" ) 
 << std::endl ;


return 0 ;
}


这样做提示:
1>正在编译...
1>MyTList_main.cpp
1>MyTList.cpp
1>正在生成代码...
1>正在链接...
1>LINK : 没有找到 E:\study\works\work_c\test\Debug\test.exe 或上一个增量链接没有生成它;正在执行完全链接
1>MyTList_main.obj : error LNK2019: 无法解析的外部符号 "public: __thiscall MyTList<int>::~MyTList<int>(void)" (??1?$MyTList@H@@QAE@XZ),该符号在函数 _main 中被引用
1>MyTList_main.obj : error LNK2019: 无法解析的外部符号 "public: __thiscall MyTList<double>::~MyTList<double>(void)" (??1?$MyTList@N@@QAE@XZ),该符号在函数 _main 中被引用
1>MyTList_main.obj : error LNK2019: 无法解析的外部符号 "public: __thiscall MyTList<char *>::~MyTList<char *>(void)" (??1?$MyTList@PAD@@QAE@XZ),该符号在函数 _main 中被引用
1>MyTList_main.obj : error LNK2019: 无法解析的外部符号 "public: bool __thiscall MyTList<char *>::erase(char *)" (?erase@?$MyTList@PAD@@QAE_NPAD@Z),该符号在函数 _main 中被引用
1>MyTList_main.obj : error LNK2019: 无法解析的外部符号 "public: unsigned int __thiscall MyTList<char *>::findaNode(char *)" (?findaNode@?$MyTList@PAD@@QAEIPAD@Z),该符号在函数 _main 中被引用
1>MyTList_main.obj : error LNK2019: 无法解析的外部符号 "public: void __thiscall MyTList<char *>::print(void)" (?print@?$MyTList@PAD@@QAEXXZ),该符号在函数 _main 中被引用
1>MyTList_main.obj : error LNK2019: 无法解析的外部符号 "public: bool __thiscall MyTList<char *>::insert(char *)" (?insert@?$MyTList@PAD@@QAE_NPAD@Z),该符号在函数 _main 中被引用
1>MyTList_main.obj : error LNK2019: 无法解析的外部符号 "public: __thiscall MyTList<char *>::MyTList<char *>(void)" (??0?$MyTList@PAD@@QAE@XZ),该符号在函数 _main 中被引用
1>MyTList_main.obj : error LNK2019: 无法解析的外部符号 "public: bool __thiscall MyTList<double>::erase(double)" (?erase@?$MyTList@N@@QAE_NN@Z),该符号在函数 _main 中被引用
1>MyTList_main.obj : error LNK2019: 无法解析的外部符号 "public: bool __thiscall MyTList<int>::erase(int)" (?erase@?$MyTList@H@@QAE_NH@Z),该符号在函数 _main 中被引用
1>MyTList_main.obj : error LNK2019: 无法解析的外部符号 "public: unsigned int __thiscall MyTList<double>::findaNode(double)" (?findaNode@?$MyTList@N@@QAEIN@Z),该符号在函数 _main 中被引用
1>MyTList_main.obj : error LNK2019: 无法解析的外部符号 "public: unsigned int __thiscall MyTList<int>::findaNode(int)" (?findaNode@?$MyTList@H@@QAEIH@Z),该符号在函数 _main 中被引用
1>MyTList_main.obj : error LNK2019: 无法解析的外部符号 "public: void __thiscall MyTList<double>::print(void)" (?print@?$MyTList@N@@QAEXXZ),该符号在函数 _main 中被引用
1>MyTList_main.obj : error LNK2019: 无法解析的外部符号 "public: bool __thiscall MyTList<double>::insert(double)" (?insert@?$MyTList@N@@QAE_NN@Z),该符号在函数 _main 中被引用
1>MyTList_main.obj : error LNK2019: 无法解析的外部符号 "public: __thiscall MyTList<double>::MyTList<double>(void)" (??0?$MyTList@N@@QAE@XZ),该符号在函数 _main 中被引用
1>MyTList_main.obj : error LNK2019: 无法解析的外部符号 "public: void __thiscall MyTList<int>::print(void)" (?print@?$MyTList@H@@QAEXXZ),该符号在函数 _main 中被引用
1>MyTList_main.obj : error LNK2019: 无法解析的外部符号 "public: bool __thiscall MyTList<int>::insert(int)" (?insert@?$MyTList@H@@QAE_NH@Z),该符号在函数 _main 中被引用
1>MyTList_main.obj : error LNK2019: 无法解析的外部符号 "public: __thiscall MyTList<int>::MyTList<int>(void)" (??0?$MyTList@H@@QAE@XZ),该符号在函数 _main 中被引用
1>E:\study\works\work_c\test\Debug\test.exe : fatal error LNK1120: 18 个无法解析的外部命令
1>生成日志保存在“file://e:\study\works\work_c\test\Debug\BuildLog.htm”
1>test - 19 个错误,0 个警告

我把成员函数的定义放到MyTList.h中,
就运行成功了,这是怎么回事?
难道是头文件包含错误?
该怎么改正?我想让成员函数的定义放到另外的文件里面。

7 个解决方案

#1


老问题了,模板类的声名和定义必须放在一起。
好像有一个方法可以不用放一起,不过我忘了,那个效果也不是很好。

应该在C++ PRIMER PLUS上有介绍

建议还是放一起吧,C++的模板库里面都是放一起的

#2


模板的声明跟定义要放在一起..
除非使用export关键字.
每天见好几回这样问模板的.

#3


一个变通的方法是在头文件中后边加入
#include "MyTList.cpp"

并把#include "MyTList.cpp"文件前边几行删去

否则使用export 关键字,用icc编译器编译

#4


用分离编译模式,但当前的编译器中好像只有Comeau C++是支持这个的。
但可以用这样的办法来实现。


/*
*MyTList.h,自定义节点类型链表;添加删除查找节点;
*/
#ifndef MYTLIST_H
#define MYTLIST_H
#include "TList.h"
#include <iostream>

template < typename T >
class MyTList
/*……*/
#include "MyTList.cpp"

#endif





#ifndef _MY_TLIST_H_
#define _MY_TLIST_H_

#include "MyTList.h"
#include "TList.h"
#include <iostream>

template < typename T >
MyTList < T >::MyTList()
/* ……*/
#endif

#5


引用 2 楼 hairetz 的回复:
模板的声明跟定义要放在一起.. 
 除非使用export关键字. 
 每天见好几回这样问模板的.



#6


引用 2 楼 hairetz 的回复:
模板的声明跟定义要放在一起..
除非使用export关键字.
每天见好几回这样问模板的.

d

或者等待export关键字的实现

#7


引用 2 楼 hairetz 的回复:
模板的声明跟定义要放在一起.. 
除非使用export关键字. 
每天见好几回这样问模板的.

测试一下了!

#1


老问题了,模板类的声名和定义必须放在一起。
好像有一个方法可以不用放一起,不过我忘了,那个效果也不是很好。

应该在C++ PRIMER PLUS上有介绍

建议还是放一起吧,C++的模板库里面都是放一起的

#2


模板的声明跟定义要放在一起..
除非使用export关键字.
每天见好几回这样问模板的.

#3


一个变通的方法是在头文件中后边加入
#include "MyTList.cpp"

并把#include "MyTList.cpp"文件前边几行删去

否则使用export 关键字,用icc编译器编译

#4


用分离编译模式,但当前的编译器中好像只有Comeau C++是支持这个的。
但可以用这样的办法来实现。


/*
*MyTList.h,自定义节点类型链表;添加删除查找节点;
*/
#ifndef MYTLIST_H
#define MYTLIST_H
#include "TList.h"
#include <iostream>

template < typename T >
class MyTList
/*……*/
#include "MyTList.cpp"

#endif





#ifndef _MY_TLIST_H_
#define _MY_TLIST_H_

#include "MyTList.h"
#include "TList.h"
#include <iostream>

template < typename T >
MyTList < T >::MyTList()
/* ……*/
#endif

#5


引用 2 楼 hairetz 的回复:
模板的声明跟定义要放在一起.. 
 除非使用export关键字. 
 每天见好几回这样问模板的.



#6


引用 2 楼 hairetz 的回复:
模板的声明跟定义要放在一起..
除非使用export关键字.
每天见好几回这样问模板的.

d

或者等待export关键字的实现

#7


引用 2 楼 hairetz 的回复:
模板的声明跟定义要放在一起.. 
除非使用export关键字. 
每天见好几回这样问模板的.

测试一下了!