不使用模板
// add.hpp
/*
**********************************************************
* Create time : 2024-07-09 16:17:02
* Author : leon
* Email : leon@^-^
* Filename : add.hpp
* Description :
**********************************************************
*/
#ifndef __ADD_HPP
#define __ADD_HPP
int add(int x, int y)
{
return x + y;
}
#endif // __ADD_HPP
// test1.cpp
/*
**********************************************************
* Create time : 2024-07-09 16:20:21
* Author : leon
* Email : leon@^-^
* Filename : test1.cpp
* Description :
**********************************************************
*/
#include "add.hpp"
#include <iostream>
void test1(int x, int y)
{
int result = add(x, y);
std::cout << "test1 add : " << result << std::endl;
}
// test2.cpp
/*
**********************************************************
* Create time : 2024-07-09 16:20:13
* Author : leon
* Email : leon@^-^
* Filename : test.cpp
* Description :
**********************************************************
*/
#include "add.hpp"
#include <iostream>
void test2(int x, int y)
{
int result = add(x, y);
std::cout << "test2 add : " << result << std::endl;
}
// main.cpp
#include "add.hpp"
#include <iostream>
void test1(int x, int y);
void test2(int x, int y);
int main()
{
int x = 100;
int y = 200;
int r = add(x, y);
std::cout << "main add : " << r << std::endl;
test1(x, y);
test2(x, y);
return 0;
}
编译结果
没有使用模板,在头文件中定义,会出现重复定义的结果,无法通过编译
使用模板
在链接阶段之前,模板没有进行实例化,因此也没有地址,在链接的时候,调用模板的地方无法通过名字在别的文件中找到模板的地址,也就无法实现模板的分离编译。
所以只能在头文件或者cpp文件中定义和实现。如果在cpp文件中定义和实现,无法在其他文件中也用到定义的函数或者类。现在测试在头文件中实现会不会出现重复定义。
/*
**********************************************************
* Create time : 2024-07-09 16:17:02
* Author : leon
* Email : leon@^-^
* Filename : add.hpp
* Description :
**********************************************************
*/
#ifndef __ADD_HPP
#define __ADD_HPP
template<typename T>
T add(T x, T y)
{
return x + y;
}
#endif // __ADD_HPP
int add(int x, int y)
{
return x + y;
}
#endif // __ADD_HPP
// test1.cpp
/*
**********************************************************
* Create time : 2024-07-09 16:20:21
* Author : leon
* Email : leon@^-^
* Filename : test1.cpp
* Description :
**********************************************************
*/
#include "add.hpp"
#include <iostream>
void test1(int x, int y)
{
int result = add(x, y);
std::cout << "test1 add : " << result << std::endl;
}
// test2.cpp
/*
**********************************************************
* Create time : 2024-07-09 16:20:13
* Author : leon
* Email : leon@^-^
* Filename : test.cpp
* Description :
**********************************************************
*/
#include "add.hpp"
#include <iostream>
void test2(int x, int y)
{
int result = add(x, y);
std::cout << "test2 add : " << result << std::endl;
}
// main.cpp
#include "add.hpp"
#include <iostream>
void test1(int x, int y);
void test2(int x, int y);
int main()
{
int x = 100;
int y = 200;
int r = add(x, y);
std::cout << "main add : " << r << std::endl;
test1(x, y);
test2(x, y);
return 0;
}
编译结果
原理
模板的特性
模板实例化:模板是一种编译时机制,只有在实际使用时才会实例化。当一个模板在头文件中定义和实现时,它并不会立即生成代码,只有在某个源文件中使用该模板并给定具体类型时,编译器才会生成相应的代码。
一次性实例化:每个模板实例(即每个具体类型的模板)在整个程序中只实例化一次。即使模板的定义和实现被包含在多个源文件中,编译器也会确保每个具体类型的模板实例只生成一次代码。
链接器的处理
内联机制:C++ 编译器通常会将模板函数视为内联函数处理。这样,在多个源文件中包含同一个头文件时,编译器会在每个包含的源文件中生成内联代码,但链接器会确保只保留一个最终实例。
外部链接:模板代码的具体实现是在头文件中提供的,但这些代码并不会在头文件中立即生成二进制代码,而是在使用时才生成。在链接阶段,链接器会处理这些实例化的代码,并去除重复的部分。