作者:周洪璋
C++模板是C++很重要的一个技术分支,可以从字面意思来理解他的作用,就相当于创建一个模板可以适配多种函数或者类等等,大大节省了工作效率。
C++ 提供了两种模板,分别为函数模板和类模板
1. 函数模板:
template<class T>
int add(T a,T b)//模板函数
{
cout<<a*b<<endl;
}
int main()
{
int a;
int b;
add(a,b);//函数模板可以自动推导参数的类型
add<int>(a,b);
}
上面是最简单的函数模板,步骤:
1: template<class t>
2:替换相应的 数据类型
如void c(int a ,int b)->void c(t a, t b),注意要同种类型才可
3:调用 c(a,b)或者是c<>(a,b)或者
c <int>(a,b)
2. 函数模板和普通模板区别:
代码1:
int add(int a,int b)
{
cout<<a+b<<endl;
}
template<class T>
int add(T a,T b)//模板函数
{
cout<<a*b<<endl;
}
void test02()
{
char a=10,b=30;
add(a,b);//调用函数模板不是同类型优先考虑模板函数,因为普通函数要自动转换,模板函数不需要
}
void test01()
{
int a=10;
char b=20;
add(a,a);//普通函数
add<>(a,a);//函数模板
add<int>(a,a);//函数模板
add(a,b);//普通函数,自动类型转换
// add<>(a,b);//error模板函数不能够自动类型转换
}
int main()
{
test02();
test01();
}
总结:
- 函数模板不允许自动类型转化 普通函数能够自动进行类型转化
- 有两个不同参数时,优先调用普通函数,因为普通函数可以隐式类型转换。
- 函数模板不允许自动类型转换,必须严格匹配类型。
- 如果传入的实参没有和普通函数的形参一样,就会优先调用函数模板,因为普通函数要自动类型转换
模板实现的原理
-
c/c++编译过程都需要经过4步编译,分别是预编译,编译,汇编,链接
分别对应 gcc -E ,gcc -s gcc -c gcc ;
hello.i hello.s hello.o hello.exe*/ -
本质是函数重载,进行二次编译,第一次先把所有的T替换实参的类型,
-
第二次在进行实际的运算,第二次就是一个普通函数。
类模板
类模板和函数模板相似,主要解决多个类功能相同但是数据类型不同的问题。
template<class T1,class T2>
class annimal
{
T1 a;
T2 b;
public:
annimal(T1 a,T2 b)
{
this->a=a;
this->b=b;
cout<<this->a<<this->b<<"类模板"<<endl;
}
};
void test03()
{
annimal<string,int>("王者荣耀",20);//显示指定
总结:
- 定义方法为:
template<class T1,class T2>
可以定义多个 class 名字自己取
2.替换掉相应的数据类型。
3.在调用该类的对象函数或者是对象成员时必须要显示该类型如:
annimal<string,int>("王者荣耀",20);
要指定王者荣耀以及20的类型,这里指定为
string和int 其实就是指定T1,和T2的数据类型
类模板派生普通类
类模板在作为基类被继承的时候,子类必须要确定基类的大小
template<class T1>
class base()
{
public:
base(T1 a)
{
a=10;
}
}
//子类继承
class son:base<int>//指定为int型
{
son():base<int>(20)//调用父类指定的构造函数,否则将会默认调用父类无参构造
{}
}
类模板类外实现
类模板的类内实现就是在类里面调用模板,上面实现的方式时类内实现,这里不在啰嗦,主要讲类外实现。
template<class T1,class T2>
class annimal
{
T1 a;
T2 b;
public:
annimal(T1 a,T2 b);
};
template<class T1,class T2>//重新定义
annimal<T1,T2>::annimal(T1 a,T2 b)//引用,否则将会成为全局函数
{
cout<<a<<" ----"<<b<<endl;
}
void test04()
{
annimal<float ,int>p(10,20);
}
总结:
1.现在内部声明,在外部定义
annimal<T1,T2>::annimal(T1 a,T2 b)//引用,否则将会成为全局函数
2.外部定义时要重新引用该模板
template<class T1,class T2>//重新定义
3。调用该函数和平常的模板类一样
annimal<int int> p(10,10);
我们类模板的成员函数是在调用是在调用时,没用调用编译器是不会创建这个函数,只有声明。
类模板的分文件问题
当在头文件定义一个类模板,类模板的成员函数在其他文件实现时,调用该类的类模板成员函数将会报错,提示你找不到相关定义,因为在调用该成员函数时会在头文件寻找,如果在该头文件找不到实现的方法,讲会报错,这就是一个分文件存在的问题。
:解决方法是写在同一个文件里面,通常都用后缀名.hpp来命名,告诉调用者这是一个类模板。
template<class T1,class T2>
class annimal
{
T1 a;
T2 b;
public:
annimal(T1 a,T2 b);
};
类模板碰到友元函数
友元函数可以直接在类模板里面定义,此时该友元函数是一个全局变量,虽然他在类模板里面定义
方法一:直接在类模板里面声明
template<class T1,class T2>
class my
{
T1 a;
T2 b;
public:
friend void other1( my<T1,T2> &p)
{
p.a=10;
cout<<p.a<<endl;
}
int ai;
};
方法二,在内部声明友元函数,在外部定义
template<class T1,class T2>
class my;//进行声明,不然执行到友元函数时会找不到my这个类
template<class T1,class T2>//这个友元函数时一个函数模板,所以在此定义,此时定义不一定要和雷类模板得名字相同
void other( my<T1 ,T2> &p)
{
cout<<"友元函数"<<endl;
}
template<class T1,class T2>
class my
{
T1 a;
T2 b;
public:
friend void other<>( my<T1 ,T2> &p);
};