模板类分开编译问题

关于模板类声明与实现分离(即声明放在.h文件,实现放在.cpp文件)的测试。


最近在写模板类的时候,分开编译模板声明和模板实现老实编译不过。看提示应该是链接不到实现的函数。

在网上查了一下,发现很多精辟的解释。


原来原因是模板的具体定义要在模板参数确定了之后才能实例化。
而在模板实例化的过程中(比如在main函数中,但只包含模板声明函数)。包含实例化的.cpp文件编译成.o文件,留了类函数的入口地址等待填充。

一般,包含普通函数的.cpp文件编译成.o文件时。函数是确定的,能编译成二进制代码。然后就有函数入口地址可以让链接程序填入调用了这个函数的.o文件中。

然后函数调用就成功了。

但是,对于模板类的实现。编译成.o文件时,仍然没有实例化。就是说模板类的实现函数不知道具体的模板函数是什么,不能实例化成一个真正的类型

(比如Vector<int> a ; //参数实例化成int,vector<int>为一个类型( 和内置类型double一样了 ))。但是没有实例化前,函数是不确定的。就是还没有编译成二进制文件。所以没有函数的入口地址提供。由于没有入口地址,链接程序在帮main函数找实例化成具体类型的模板找实现函数时找不到,就提示链接错误了。
既然知道哪里粗了问题,就可以解决问题了。解决的办法就是让实例化了模板的.cpp文件可以看到函数实现就行了。
这里有两个办法。
1、直接把函数声明和函数实现全部放在同一个.h文件里面。这样引用.h文件的时候,声明和实现都直接展开在实例化的.cpp文件里面
这样编译的时候就能找到函数的入口地址了。
2、函数声明和函数实现分开实现。在实例化模板的地方#include "xxx.cpp",即直接包含.cpp文件,这样也能找到函数入口。如我下面测试的一样。


其实,我之前看到一般文章有说,如果把声明和实现都放在同一个.h文件里面,在不同的.cpp文件里面以不同的参数实现模板的时候会
报重覆定义的错误。但是我没遇到过。如果以后发现再补充回来吧。

templateclass.h

#ifndef _TEM_H__
#define _TEM_H__

#include <iostream>
using namespace std;

template <class Elem>
class List {
    private:
	Elem data;
    public:
	List(Elem a ) {
	    data = a;
	}
	void print( void );
};

//#include "templateclass.cpp"
#endif


templateclass.cpp

#include "templateclass.h"

template <class Elem>
void List<Elem>::print( ) {
    cout << data << endl;
}
double.cpp
#include "templateclass.h"
#include "templateclass.cpp"


void doubleprint( double para ) {
    List<double> object( para );
    object.print( );
}


int.cpp
#include "templateclass.h"

#include "templateclass.cpp"
void intprint( int para ) {
    List<int> object( para );
    object.print( );
}


mainfun.cpp
//#include <iostream>
//using namespace std;

void doubleprint( double );
void intprint( int );
int main( int argc, char *argv[] ) {
    doubleprint( 3.5 );
    intprint( 19 );
    return 0;
}


//makefile
tao:	double.o int.o mainfun.o templateclass.o
	g++ -o tao double.o int.o mainfun.o templateclass.o

double.o: templateclass.h double.cpp
	g++ -c double.cpp

int.o:	templateclass.h int.cpp
	g++ -c int.cpp

templateclass.o: templateclass.h templateclass.cpp
	g++ -c templateclass.cpp

mainfun.o: double.cpp int.cpp mainfun.cpp
	g++ -c mainfun.cpp



参考: 

超通俗地解释模板分离编译

http://blog.youkuaiyun.com/pongba/article/details/19130

### 模板类的概念与作用 模板类是 C++ 中实现泛型编程的核心机制之一,它允许定义通用的类,类的成员变量和成员函数的类型可以使用虚拟类型参数来表示。在类实例化时,这些虚拟类型参数会被具体的类型替代,从而实现一套代码适用于多种数据类型的目标。这种机制显著减少了代码冗余,并提高了代码的复用性和可维护性[^1]。 模板类的定义方式与函数模板类似,通过关键字 `template` 引入模板参数列表,然后定义类的结构。例如,一个简单的模板类可以用于表示一个通用的容器或数据结构,支持不同类型的数据存储和操作。这种方式与 C++ 面向对象编程思想(封装、继承、多态)相结合,进一步增强了代码的灵活性和可扩展性[^1]。 ```cpp template <typename T> class Box { private: T content; public: Box(T value) : content(value) {} T getContent() const { return content; } }; ``` ### 模板类的使用方法 模板类的使用包括定义模板类、实例化模板类以及调用其成员函数。定义模板类时,需要在类名前加上模板参数列表,例如 `template <typename T>`,其中 `T` 是一个占位符类型名。在类的成员函数定义中,可以使用 `T` 来表示类型,这些函数可以是内联定义的,也可以在类外定义,但需要在函数定义前再次声明模板参数列表[^2]。 模板类的实例化与普通类不同,需要在类名后指定具体类型,例如 `Box<int> box(5);`。由于模板类没有自动类型推导功能,因此必须显式指定模板参数类型,不能省略 `<>`。模板类还可以在模板参数列表中提供默认参数,但这些默认参数必须位于参数列表的末尾,并且需要指定数据类型[^2]。 ```cpp #include <iostream> template <typename T> class Box { private: T content; public: Box(T value) : content(value) {} T getContent() const { return content; } }; int main() { Box<int> boxInt(10); Box<std::string> boxString("Hello"); std::cout << boxInt.getContent() << std::endl; std::cout << boxString.getContent() << std::endl; return 0; } ``` ### 模板类的分文件编写 模板类的声明和实现通常需要放在同一个文件中,因为模板类编译和链接机制不同于普通类。如果将模板类的声明和实现分开到不同的文件中,可能会导致链接错误。解决这一问题的常见方法有两种:一种是将实现文件(如 `.cpp`)包含到使用模板类的源文件中;另一种是将声明和实现合并到一个文件中,通常使用 `.hpp` 或 `.h` 作为文件后缀[^3]。 ```cpp // person.hpp template <typename T1, typename T2> class Person { private: T1 name; T2 age; public: Person(T1 n, T2 a) : name(n), age(a) {} void showPerson() { std::cout << "Name: " << name << ", Age: " << age << std::endl; } }; // main.cpp #include "person.hpp" int main() { Person<std::string, int> p("Tom", 10); p.showPerson(); return 0; } ``` ### 总结 模板类的作用在于提供一种机制,使得开发者能够编写与数据类型无关的通用代码,从而提高代码的复用性和灵活性。模板类的使用方法包括定义模板类、实例化模板类以及调用其成员函数。模板类的分文件编写需要注意模板的编译和链接机制,通常需要将声明和实现放在同一个文件中或者在使用时包含实现文件。模板类是 C++ 泛型编程思想的核心实现之一,与面向对象编程思想相结合,进一步增强了 C++ 的功能和灵活性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值