1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > c++—模板(函数模板 类模板)

c++—模板(函数模板 类模板)

时间:2020-11-08 02:25:06

相关推荐

c++—模板(函数模板 类模板)

1. 模板是解决代码复用的最优解,其原理是为功能不变而参数数据类型不同的的程序提供一种代码共享机制,模板也是一种多态的实现,可以在编译器协助开发者生成代码,从而演化为面向模板元编程(面向编译器),是一种解决良好代码维护性、复用性的工具;

2. 在C语言中也可以进行宏定义进行函数模板,但是存在两个缺点:①不安全,因为宏定义只是简单的替换,不进行参数类型检查;②只可实现简单函数,不适合复杂函数;

3. 模板主要应用于函数模板、类模板两种情况下;

4. 函数模板:

(1)语法

#include <iostream>#include <string>template<typename T> //函数模板声明T my_max(const T &a, const T &b){return a > b ? a : b;}int main(){cout << my_max<int>(5,6) << endl; //注意这里<int>指明T的类型return 0;}

使用步骤:

①先声明函数模板:template<typename T>

②编写函数,注意里面的形参的类型均用T代替;

③在main函数中调用函数模板时,需要在函数名后面跟<int>或<char>等,表明本次调用的函数模板的类型是int还是char;

(2)内部原理

①函数模板只是个模板,不能实际执行;

②在调用时,会根据指定的参数类型,依据函数模板实例化,生成模板函数;

③函数模板可以重载,条件均是前期重载定义的条件:形参表个数或者类型参数不同;

(3)函数模板和普通函数的执行优先级

①先执行参数完全匹配的自定义普通函数;

②次之:参数匹配的模板函数;

(4)可变参数模板:递归思路

#include <iostream>void test() //递归结尾,即参数为0时结束{}template <typename T, typename...U> //注意这个形式,有...void tes(T && first, U&&... others){cout<<first<<endl;test(others...);}//可变参数函数,使用第一个参数first做一些事情后,继续递归其他参数;//编译器内部对每一次递归调用形式(因为参数个数变化),都生成了固定的模板函数(实例化),会有很多;

5. 类模板

(1)语法

①在类的定义前加模板声明:template<typename T>,T就是类型代名词;

②在类内所有需要用到数据类型的都用T代替;

③若成员函数在类外定义,则每个成员函数前面都要加相同的类模板声明,建议在类内定义;

④要使得成员函数的输出类型不受该类整体的类型模板声明T的限制,则可写成类的成员函数模板,使得该成员函数依据新的类型单独变化;

⑤可以利用using给模板起别名;

template <typename T> //类模板声明class Stack{public:Stack();void push(T num);T pop();template<typename U> //该成员函数不受T的限制,根据实际U的类型而定void print(U num){cout<<num<<endl;}private:int top;T data[SIZE];}template void print<int>(int num); //即针对int类型只实例化一次,只生成一个模板函数;int mian(){Stack<int>s1; //调用形式return 0;}

(2)隐式实例化、显式实例化

①隐式实例化会降低效率,因为每次调用模板时都会生成模板函数,无论前后的类型是否一致;

②显式实例化,相当于只生成一次模板函数,后面的再调用的隐式就不会再实例化了,本质上相当于函数声明,即调用模板时,前置声明一次,如下:

template void print<int>(const int &t);详见上图;

(3)typename作用:在类模板中或者函数模板中访问一个类或者结构体中的自定义类型的时候,用typename修饰,放置语法歧义;

6. 模板的全特化与偏特化

(1)特化处理的目的是对特殊的类型做特殊的处理,以求达到特定类型特定的功能(例如多输出几句话、特定的处理等等);

(2)全特化:注意在全特化的类前加template<>

//类模板(泛化)template <typename T1, typename T2>class A{T1 data1;T2 data2;};//模板的全特化template <> //注意这里的全特化声明class A<int double> //这里也要指定特化的具体类型{int data1;double data2;};

(3)偏特化示例,注意指定具体类型

//类模板(泛化)template <typename T1, typename T2, typename T3>class B{public:void myfunc(T2 b){cout<<"泛化函数"<<endl;}};//偏特化template <typename T2> //没有偏特化的参数类型还要注明,不能丢class B<int, T2, int>//已经偏特化的参数类型要在类型定义后面加上具体类型{public:void myfunc(T2 b){cout<<"偏特化函数"<<endl;} };

(4)全特化与偏特化的区别

①全特化实际是更加具体地指明所有的参数的固定类型;

②偏特化实际是一部分参数明确了具体的类型,而不是所有的;或者所有参数都降低了类型范围,减少了系统类型推导时间,例如T→T*,或者const修饰;

③若在特化处理中出现偏特化冲突时,用全特化处理;

④一般用类型的全特化较多,函数的全特化尽量不要用,而是直接写一个自定义的普通函数;

(5)模板元编程

为编译器而编码,旨在利用编译期间为生成代码而进行的编程;工作原理是利用类模板,通过编译器生成各种各类的模板类;同时利用const等关键字让系统自动回收垃圾;

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。