C++进阶-1-模板基础(函数模板、类模板)
C++进阶 模板
1.1 函数模板
1 #include2 using namespace std; 3 4 // 模板 5 6 // 模板的简单实例 7 // 要求: 8 // 1.利用函数模板封装一个排序函数,可以对不同数据类型数组进行排序 9 // 2.排序规则由大到小,排序算法为:选择排序 10 // 3.分别利用char数组和int数组进行测试 11 12 // 交换函数模板 13 template<class T> 14 void mySwap(T& a, T& b) { 15 T temp = a; 16 a = b; 17 b = temp; 18 } 19 20 // 排序算法模板 21 template<class T> // 也可以写typename 22 void mySort(T arr[], int len) { 23 // 选择排序 24 for (int i = 0; i < len; i++) { 25 int max = i; // 认定最大值下标 26 for (int j = i + 1; j < len; j++) { 27 // 认定的最大值 比 遍历出的最大值 要小,说明 j 下标的元素才是真正的最大值 28 if (arr[max] < arr[j]) { 29 max = j; // 更新最大值下标 30 } 31 } 32 if (max != i) { 33 // 交换下标为max和i的元素 34 mySwap(arr[max], arr[i]); 35 } 36 } 37 } 38 39 // 打印数字内容模板 40 template<class T> 41 void printArray(T arr[], int len) { 42 for (int i = 0; i < len; i++) { 43 cout << arr[i] << " "; 44 } 45 cout << endl; 46 } 47 48 49 void test01() { 50 51 // 测试数组 char类型 52 char charArr[] = "badcfe"; 53 int num_charArray = sizeof(charArr) / sizeof(char); 54 mySort(charArr, num_charArray); 55 printArray(charArr, num_charArray); 56 57 // 测试数组 int类型 58 int intArray[] = { 1, 3, 2, 6, 4, 5, 7 }; 59 int num_int = sizeof(intArray) / sizeof(int); 60 mySort(intArray, num_int); 61 printArray(intArray, num_int); 62 } 63 64 int main() { 65 66 test01(); 67 68 system("pause"); 69 70 return 0; 71 } 72 73 // 总结 74 // C++除了面向对象编程思想外,还有 泛型编程 以及 STL 技术 75 // 76 // 模板:建立通用的模具,大大提高代码的复用性 77 // 模板不可以直接使用,它只是一种框架 78 // 模板的通用并不是万能的 79 // 80 // 模板分为:函数模板与类模板 81 // 82 // 83 // 函数模板: 84 // 85 // 模板的作用:建立一个通用函数,其函数返回值类型和形参类型都可以不具体制定,用一个虚拟的类型来表示 86 // 语法: 87 // template // typename也可以写成 class 88 // 函数生命或定义 89 // 解释:T 通用的数据类型,名称可以替换,通常为大写字母 90 // 91 // 函数模板的使用方式有两种:自动类型推导、显示指定类型 92 // 93 // 模板注意事项: 94 // 1.自动类型推导方式,必须推导出一致的数据类型T,才可以使用 95 // 2.模板必须要确定出T的数据类型,才可以使用 96 // 97 // 普通函数与函数模板的区别 98 // 1.普通函数调用可以发生自动类型转换(隐式转换); 99 // 2.函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换 100 // 3.如果利用显示指定类型的方式,可以发生隐式转换; 101 // 102 // 所以,建议使用显示指定类型的方式,调用函数模板,因为可以自己确定通用类型 103 // 104 // 普通函数与函数模板的调用规则 105 // 1.如果函数模板和普通函数都有可以实现,编译器会优先调用普通函数 106 // 2.可以通过空模板参数列表来强制调用函数模板(加<>) 107 // 3.函数模板也可以发生重载 108 // 4.如果利用函数模板可以产生更好的匹配,优先调用函数模板 109 // 110 // 所以,既然提供了函数模板,就最好不要再提供普通函数了,否则出现二义性 111 // 112 // 模板的局限性 113 // 1.模板的通用型不是万能的 114 // 利用具体化的模板,可以解决自定义类型的通用化 115 // 学习模板不是为了写模板,而是在STL能够运用系统提供的模板 116 // 117
1.2 类模板
#include#include<string> using namespace std; // 类 模板 // 示例1 //template // 类模板可以有默认参数 template<class Nametype, class Agetype = int> class Person1 { public: Person1(Nametype name, Agetype age) { this->m_Name = name; this->m_Age = age; } void showPerson() { cout << "姓名:" << this->m_Name << " 年龄:" << this->m_Age << endl; } //string m_Name; //int m_Age; Nametype m_Name; Agetype m_Age; }; void test01() { //Person p1("Tom", 19); // 报错,无法自动推导类型 //Person1 p1("Tom", 19); ,> Person1<string> p1("Tom", 19); p1.showPerson(); } // 示例2 // 类模板对象做函数参数,三种传入方式 template<class T1, class T2> class Person2 { public: Person2(T1 name, T2 age) { this->m_Name = name; this->m_Age = age; }; void showPerson() { cout << "姓名:" << this->m_Name << " 年龄:" << this->m_Age << endl; } T1 m_Name; T2 m_Age; }; // 1.指定传入类型 void printPerson1(Person2<string, int>& p) { p.showPerson(); } // 2.参数模板化 template<class T1, class T2> void printPerson2(Person2& p) { p.showPerson(); // 看一下编译器推导出的类型 cout << "T1的类型为:" << typeid(T1).name() << endl; cout << "T2的类型为:" << typeid(T2).name() << endl; } // 3.整个类模板化 template<class T> void printPerson3(T& p) { p.showPerson(); cout << "T的类型为:" << typeid(T).name() << endl; } void test02() { Person2<string, int>p("小明", 20); // 1.指定传入类型(最常用) printPerson1(p); // 2.参数模板化 printPerson2(p); // 3.整个类模板化 printPerson3(p); } // 示例3 类模板与继承 template<class T> class Base { T m; }; // class Son:pubic Base // 错误,C++编译需要给子类分配内存,必须知道父类中T的类型才可以向下继承 class Son1 :public Base<int> { // 必须指定一个类型 }; // 如果想灵活制定出父类中T的类型,子类也需要变为模板 template<class T1, class T2> class Son2 :public Base ,>{ public: Son2() { cout << "T1的类型为:" << typeid(T1).name() << endl; cout << "T2的类型为:" << typeid(T2).name() << endl; } T1 obj; }; void test03() { Son1 s1; Son2<int, char> s2; } // 示例4 类模板成员函数类外实现 template<class T1, class T2> class Person4 { public: Person4(T1 name, T2 age); // 类内声明 //{ // this->m_Name = name; // this->m_Age = age; //}; void showPerson(); // 类内声明 //{ // cout << "姓名:" << this->m_Name << " 年龄:" << this->m_Age << endl; //} T1 m_Name; T2 m_Age; }; // 类外实现 template<class T1, class T2> Person4 ::Person4(T1 name, T2 age) { this->m_Name = name; this->m_Age = age; } template<class T1, class T2> void Person4 ,>::showPerson() { cout << "姓名:" << this->m_Name << " 年龄:" << this->m_Age << endl; } void test04() { Person4<string, int> p4("张三", 100); p4.showPerson(); } int main() { // 类模板初识 //test01(); // 类模板对象做函数参数 //test02(); // 类模板与继承 //test03(); // 类模板成员函数类外实现 test04(); system("pause"); return 0; } // 总结 // // 模板分为:函数模板与类模板 // // // 类模板: // // 类模板作用:建立一个通用类,类中的成员 数据类型可以不具体制定,用一个虚拟类型来代表 // // 语法: // template ,>// typename可以写成 class,与typename没啥具体区别 // 类 // // 类模板与函数模板区别: // 1.类模板没有自动类型推导的使用方式,所以必须指定 // 2.类模板在模板参数列表中可以有默认参数 // // 类模板中成员函数的创建时机 // 1.普通类中的成员函数一开始就可以创建 // 2.类模板中的成员函数在调用时才开始创建 // // 类模板对象做函数参数 // 类模板实例化出对象,向参数传参 // 三种传参方式: // 1.制定传入类型 直接显示对象的数据类型(最常用) // 2.参数模板化 将对象中的参数变为模板进行传递 // 3.整个类模板化 将这个对象类型 模板化进行传递 // // 类模板与继承 // 1.当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类T的类型 // 2.如果不指定,编译器无法给子类分配内存 // 3.如果想灵活制定出父类中T的类型,子类也需要变为模板 // // 类模板的成员函数可以类外实现(类内声明,类外实现) // 需要添加:1.作用域;2.参数模板/参数模板列表 // // 类模板份文件编写 // 问题:类模板中成员函数创建时机是在 调用阶段 ,导致分文件编写时链接不到 // // 解决: // 方式1:直接包含.cpp源文件 // 方式2:将声明和实现写到同一个文件中,并更改后缀名为.hpp hpp是约定的名称,并不强制 // // 类模板与友元 // 全局函数类内实现:直接在类内声明友元即可(建议使用类内实现) // 全局函数类外实现:需要提前让解释器知道全局函数的存在 // 1.加一个空模板的参数列表<> // 2.把代码剪切到代码文件的最上方,让编译器先看到 // 3.加入类的声明,提前让编译器看到模板类 //
Original: https://www.cnblogs.com/LYH-win/p/16225837.html
Author: Thomas_kaka
Title: C++进阶-1-模板基础(函数模板、类模板)
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/567827/
转载文章受原作者版权保护。转载请注明原作者出处!