1.函数模板
-
函数模板声明:
template <typename T>
template是模板关键字,typename(或class)是声明数据类型参数标识符的关键字,用以说明它后面的标识符是数据类型标识符。以下的数据类型可以用后面的标识符代替。函数模板的声明和定义中间不能有其他语句,否则会报错。
-
函数模板定义及调用
void swap_(T &a, T &b) { T c; c = a; a = b; b = c; } int main() { int a = 10; int b = 20; swap_(a, b); char c1 = 'a'; char c2 = 'b'; swap_(c1, c2); cout << a << " " << b << endl; cout << c1 << " " << c2 << endl; system("pause"); }
主函数调用时传递形参的类型int char会替代T,调用时可以显示的调用,即swap_<int>(a,b);
-
函数模板和普通函数
两者的区别: 普通函数能够进行自动类型转换,而函数模板不允许进行自动类型转换!
(这条在程序中目前还没有成功实现)
函数模板和普通函数相同时的调用机制
- 函数模板也可以重载(返回值类型不是函数重载的标准)
- 优先选择普通函数,若一定要调用模板函数,在调用时加<>
- 若函数模板匹配性更好,则选择模板函数
- 若调用时,两者都不满足,则选择普通函数,进行隐式的类型转换
-
编译器调用模板函数的机制
- 函数模板并不能处理或能够处理任意函数
- 函数模板是通过具体的类型,由编译器产生不同的函数
- 编译器会对函数模板进行两次编译:
在声明的地方对模板代码本身进行编译
在调用的地方对参数替换后的代码进行编译
2.类模板
单个类模板的基本语法
template <typename T> class A { public: A(T a) { this->a = a; } public: void printA() { cout << "a=" << a << endl; } private: T a; };
- 类模板用于实现类所需数据的类型形参化,在上面的程序中体现在成员a上。
int main() { A<int> a1(10); a1.printA(); system("pause"); }
- 调用时一定要在类名后加上具体的类型,即上程序中的<int>,如果不加会编译不通过,因为编译器不知道如何分配内存。
类模板是抽象化的 ====> 类具体化(<int>) ====> 实现具体变量的使用
- 类模板对象做函数参数和定义类对象时一样,也要加上具体的类型!
int main() { A<int> a1(10); a1.printA(); system("pause"); }
继承派生类模板
- 普通派生类
派生类继承于一个模板类,要注意具体化模板类。
class B :public A<int>
继承时,编译器要知道基类具体的类型是什么样的,也就是说要知道基类所占内存是多少,才能知道给派生类分配多大的内存。
class B :public A<int> { public: B(int a, int b) :A<int>(a) { this->b = b; } private: int b; };
派生类继承时会继承基类的构造函数,构造函数定义了就要使用,但是派生类与基类构造函数不匹配,找不到对应的构造函数,所以派生类中要重新写构造函数,添加基类的参数列表。
- 模板派生类
注意点和普通派生类一样
template <typename T> class C :public A<T> { public: C(T c, T a) :A<T>(a) { this->c = c; } private: T c; public: void printC() { cout << "c=" << c << endl; } };
来源:https://www.cnblogs.com/cyj-on-the-road/p/7806960.html