资讯专栏INFORMATION COLUMN

(黑马)C++提高编程笔记(未完)

Jenny_Tong / 2153人阅读

摘要:文章目录模板模板的概念函数模板函数模板语法函数模板注意事项函数模板案例普通函数与函数模板的区别普通函数与函数模板的调用规则模板的局限性类模板类模板语法类模板与函数模板区别类模板中成员函数创建时机类模板对象做函数参数类模


本博客只为方便后期复习,不做其他用途!
本博客配套视频:视频链接
本博客参考博客:博客链接

其他博客链接:
1、C++入门篇
2、C++核心篇


本阶段主要针对C++泛型编程和STL技术做详细讲解,探讨C++更深层的使用

1 模板

1.1 模板的概念

模板就是建立通用的模具,大大提高复用性

模板的特点:

  • 模板不可以直接使用,它只是一个框架
  • 模板的通用并不是万能的

1.2 函数模板

  • C++另一种编程思想称为 泛型编程 ,主要利用的技术就是模板
  • C++提供两种模板机制:函数模板和类模板

1.2.1 函数模板语法

函数模板作用:建立一个通用函数,其函数返回值类型和形参类型可以不具体制定,用一个虚拟的类型来代表。

语法:

</>复制代码

  1. template<typename T>函数声明或定义

解释:

  • template:声明创建模板
  • typename:表面其后面的符号是一种数据类型,可以用class代替
  • T:通用的数据类型,名称可以替换,通常为大写字母

</>复制代码

  1. #includeusing namespace std;//函数模板//两个整型交换函数void swapInt(int &a, int &b) {
  2. int temp = a;
  3. a = b;
  4. b = temp;}//交换两个浮点型函数void swapDouble(double& a, double& b) {
  5. double temp = a;
  6. a = b;
  7. b = temp;}//函数模板template<typename T> //声明一个模板,告诉编译器后面代码中紧跟着的T不要报错,T是一个通用数据类型void mySwap(T& a, T& b) {
  8. T temp = a;
  9. a = b;
  10. b = temp;}void test01() {
  11. float a = 10;
  12. float b = 20;
  13. //两种方式使用函数模板
  14. //1、自动类型推导
  15. mySwap(a, b);
  16. cout << "a:" << a << endl;
  17. cout << "b:" << b << endl;
  18. cout << "/n";
  19. //2、显示指定类型
  20. mySwap<float>(a, b);
  21. cout << "a:" << a << endl;
  22. cout << "b:" << b << endl;}int main() {
  23. test01();
  24. system("pause");
  25. system("cls");}

总结:

  • 函数模板利用关键字 template
  • 使用函数模板有两种方式:自动类型推导、显示指定类型
  • 模板的目的是为了提高复用性,将类型参数化

1.2.2 函数模板注意事项

注意事项:

  • 自动类型推导,必须推导出一致的数据类型T,才可以使用
  • 模板必须要确定出T的数据类型,才可以使用

</>复制代码

  1. //利用模板提供通用的交换函数template<class T>void mySwap(T& a, T& b){
  2. T temp = a;
  3. a = b;
  4. b = temp;}// 1、自动类型推导,必须推导出一致的数据类型T,才可以使用void test01(){
  5. int a = 10;
  6. int b = 20;
  7. char c = "c";
  8. mySwap(a, b); // 正确,可以推导出一致的T
  9. //mySwap(a, c); // 错误,推导不出一致的T类型}// 2、模板必须要确定出T的数据类型,才可以使用template<class T>void func(){
  10. cout << "func 调用" << endl;}void test02(){
  11. //func(); //错误,模板不能独立使用,必须确定出T的类型
  12. func<int>(); //利用显示指定类型的方式,给T一个类型,才可以使用该模板}int main() {
  13. test01();
  14. test02();
  15. system("pause");
  16. return 0;}

总结:使用模板时必须确定出通用数据类型T,并且能够推导出一致的类型

1.2.3 函数模板案例

案例描述:
利用函数模板封装一个排序的函数,可以对不同数据类型数组进行排序
排序规则从大到小,排序算法为选择排序
分别利用char数组和int数组进行测试

</>复制代码

  1. #includeusing namespace std;//实现通用 对数组进行排序的函数//从大到小 选择排序//测试 char数组、 int数组//交换函数模板template<class T>void mySwap(T& a, T& b) {
  2. T temp = a;
  3. a = b;
  4. b = temp;}//排序算法:选择排序,每次选择最大的一个放在前面template<class T>void mySort(T arr[], int len) {
  5. for (int i = 0; i < len; i++) {
  6. int max = i; //认定最大值的下标
  7. for (int j = i + 1; j < len; j++) {
  8. if (arr[max] < arr[j]) {
  9. max = j;
  10. }
  11. }
  12. if (max != i) {
  13. //交换max和i元素
  14. mySwap(arr[max], arr[i]);
  15. }
  16. }}//提供打印数组模板template<class T>void printArray(T arr[], int len) {
  17. for (int i = 0; i < len; i++) {
  18. cout << arr[i] << " ";
  19. }
  20. cout << endl;}void test01() {
  21. //测试char数组
  22. char charArr[] = "badcfe";
  23. int num = sizeof(charArr) / sizeof(char);
  24. mySort(charArr, num);
  25. printArray(charArr, num);}void test02() {
  26. //测试int数组
  27. int intArr[] = { 7,5,1,3,9,2,4,6,8 };
  28. int num = sizeof(intArr) / sizeof(int);
  29. mySort(intArr, num);
  30. printArray(intArr, num);}int main() {
  31. test01();
  32. test02();
  33. system("pause");
  34. system("cls");}

</>复制代码

  1. f e d c b a9 8 7 6 5 4 3 2 1请按任意键继续. . .

1.2.4 普通函数与函数模板的区别

普通函数与函数模板区别:

  • 普通函数调用时可以发生自动类型转换(隐式类型转换)
  • 函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换
  • 如果利用显示指定类型的方式,可以发生隐式类型转换

</>复制代码

  1. #includeusing namespace std;//普通函数和函数模板的区别//1、普通函数调用可以发生隐式类型转换//2、函数模板 用自动类型推导,不可以发生隐式类型转换//3、函数模板 用显示指定类型,可以发生隐式类型转换//普通函数int myAdd01(int a, int b) {
  2. return a + b;}//函数模板template<class T>T myAdd02(T a, T b) {
  3. return a + b;}void test01() {
  4. int a = 10;
  5. int b = 20;
  6. char c = "c"; //99
  7. //cout << myAdd01(a, b) << endl;
  8. cout << myAdd01(a, c) << endl;
  9. //1、自动类型推导 不会发生隐式类型转换
  10. //cout << myAdd02(a, c) << endl; //报错,无法推导出一致的T
  11. //2、显示指定类型 会发生隐式类型转换
  12. cout << myAdd02<int>(a, c) << endl;
  13. cout << myAdd02<char>(a, c) << endl;}int main() {
  14. test01();
  15. system("pause");
  16. system("cls");}

总结:建议使用显示指定类型的方式,调用函数模板,因为可以自己确定通用类型T

1.2.5 普通函数与函数模板的调用规则

调用规则如下:

  1. 如果函数模板和普通函数都可以实现,优先调用普通函数
  2. 可以通过空模板参数列表来强制调用函数模板
  3. 函数模板也可以发生重载
  4. 如果函数模板可以产生更好的匹配,优先调用函数模板

</>复制代码

  1. #includeusing namespace std;//普通函数与函数模板的调用规则//1、如果函数模板和普通函数都可以调用,优先调用普通函数//2、可以通过空模板参数列表 强制调用 函数模板//3、函数模板可以发生函数重载//4、如果函数模板可以产生更好的匹配,优先调用函数模板void myPrint(int a, int b){
  2. cout << "调用的普通函数" << endl;}template<class T>void myPrint(T a, T b) {
  3. cout << "调用的模板" << endl;}template<class T>void myPrint(T a, T b, T c) {
  4. cout << "调用重载的模板" << endl;}void test01() {
  5. int a = 10;
  6. int b = 20;
  7. myPrint(a, b); //调用的普通函数
  8. //通过空模板参数列表,强制调用函数模板
  9. myPrint<>(a, b); //调用模板
  10. myPrint<>(a, b, 100); //调用重载的模板
  11. //如果函数模板可以产生更好的匹配,优先调用函数模板
  12. char c1 = "a";
  13. char c2 = "b";
  14. myPrint(c1, c2); //调用模板}int main() {
  15. test01();
  16. system("pause");
  17. system("cls");}

</>复制代码

  1. 调用的普通函数调用的模板调用重载的模板调用的模板请按任意键继续. . .

总结:既然提供了函数模板,最好就不要提供普通函数,否则容易出现二义性

1.2.6 模板的局限性

局限性:模板的通用性并不是万能的

</>复制代码

  1. template<class T>
  2. void f(T a, T b)
  3. {
  4. a = b; }

在上述代码中提供的赋值操作,如果传入的a和b是一个数组,就无法实现了

</>复制代码

  1. template<class T>
  2. void f(T a, T b)
  3. {
  4. if(a > b) { ... } }

在上述代码中,如果T的数据类型传入的是像Person这样的自定义数据类型,也无法正常运行

因此C++为了解决这种问题,提供模板的重载,可以为这些特定的类型提供具体化的模板

</>复制代码

  1. #includeusing namespace std;//模板局限性//特定数据类型 需要用具体方式做特殊实现class Person {public:
  2. Person(string name, int age) {
  3. this->m_Name = name;
  4. this->m_Age = age;
  5. }
  6. //姓名
  7. string m_Name;
  8. //年龄
  9. string m_Age;};//对比两个数据是否相等函数template<class T>bool myCompare(T& a, T& b) {
  10. if (a == b) {
  11. return true;
  12. }
  13. else {
  14. return false;
  15. }}//利用具体化Person的版本实现代码,具体化优先调用template<> bool myCompare(Person& p1, Person& p2) {
  16. if (p1.m_Name == p2.m_Name && p1.m_Age == p2.m_Age) {
  17. return true;
  18. }
  19. else {
  20. return false;
  21. }}void test01() {
  22. int a = 10;
  23. int b = 20;
  24. bool ret = myCompare(a, b);
  25. if (ret) {
  26. cout << "a == b" << endl;
  27. }
  28. else {
  29. cout << "a != b" << endl;
  30. }}void test02() {
  31. Person p1("Tom", 10);
  32. Person p2("Tom", 10);
  33. bool ret = myCompare(p1, p2);
  34. if (ret) {
  35. cout << "p1 == p2" << endl;
  36. }
  37. else {
  38. cout << "p1 != p2" << endl;
  39. }}int main() {
  40. test01();
  41. test02();
  42. system("pause");
  43. system("cls");}

总结:

  • 利用具体化的模板,可以解决自定义类型的通用化
  • 学习模板并不是为了写模板,而是在STL能够运用系统提供的模板

1.3 类模板

1.3.1 类模板语法

类模板作用:建立一个通用类,类中的成员 数据类型可以不具体制定,用一个虚拟的类型来代表。
语法:

</>复制代码

  1. template<typename T>

解释:

  • template:声明创建模板
  • typename:表面其后面的符号是一种数据类型,可以用class代替
  • T:通用的数据类型,名称可以替换,通常为大写字母

</>复制代码

  1. #includeusing namespace std;//类模板template<class NameType, class AgeType>class Person {public:
  2. Person(NameType name, AgeType age) {
  3. this->m_Name = name;
  4. this->m_Age = age;
  5. }
  6. void showPerson() {
  7. cout << "name:" << this->m_Name << endl;
  8. cout << "age:" << this->m_Age << endl;
  9. }
  10. NameType m_Name;
  11. AgeType m_Age;};void test01() {
  12. Person<string, int> p1("张三", 18);
  13. cout << p1.m_Name << "," << p1.m_Age << endl;
  14. p1.showPerson();}int main() {
  15. test01();
  16. system("pause");
  17. system("cls");}

</>复制代码

  1. 张三,18name:张三age:18请按任意键继续. . .

总结:类模板和函数模板语法相似,在声明模板template后面加类,此类称为类模板

1.3.2 类模板与函数模板区别

类模板与函数模板区别主要有两点:

  • 类模板没有自动类型推导的使用方式
  • 类模板在模板参数列表中可以有默认参数

</>复制代码

  1. #includeusing namespace std;//类模板和函数模板区别template<class NameType, class AgeType = int>class Person {public:
  2. Person(NameType name, AgeType age) {
  3. this->m_Name = name;
  4. this->m_Age = age;
  5. }
  6. void showPerson() {
  7. cout << "name:" << this->m_Name << endl;
  8. cout << "age:" << this->m_Age << endl;
  9. }
  10. NameType m_Name;
  11. AgeType m_Age;};void test01() {
  12. //Person p("张三", 18); //1、类模板没有自动类型推导使用方式
  13. Person<string, int> p("张三", 18);
  14. p.showPerson();}//2、类模板在模板参数列表中可以有默认参数void test02() {
  15. Person<string> p2("李四", 20); //后一个参数默认整型, 默认参数只有类模板有,函数模板没有
  16. p2.showPerson();}int main() {
  17. test01();
  18. test02();
  19. system("pause");
  20. system("cls");}

</>复制代码

  1. name:张三age:18name:李四age:20请按任意键继续. . .

总结:

  1. 类模板使用只能用显示指定类型方式
  2. 类模板中的模板参数列表可以有默认参数

1.3.3 类模板中成

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/122421.html

相关文章

  • C++核心编程黑马程序员学习笔记(未完)(更新于2021/9/23)

    摘要:只读目的是防止程序意外地修改了它的指令。全局区存放全局变量静态变量和常量除了修饰的局部变量。程序结束时由操作系统释放。由编译器自动分配和释放。注意不要返回局部变量的地址。 ...

    zhongmeizhi 评论0 收藏0
  • 系统地学习C++

    摘要:本书主要围绕一系列逐渐复杂的程序问题,以及用以解决这些问题的语言特性展开讲解。你不只学到的函数和结构,也会学习到它们的设计目的和基本原理。因此我们把精力集中在最有价值的地方。本书不仅是对模板的权威解释,而且本书还深入地介绍了其他一般的思想。 C++ 入门教程(41课时) - 阿里云大学 C+...

    joyqi 评论0 收藏0
  • 最最最常见的Java面试题总结——第二周

    摘要:与都继承自类,在中也是使用字符数组保存字符串,,这两种对象都是可变的。采用字节码的好处语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点。 String和StringBuffer、StringBuilder的区别是什么?String为什么是不可变的? String和StringBuffer、StringBuilder的区别 可变性...

    yearsj 评论0 收藏0
  • HTML

    摘要:目前,中关村黑马程序员训练营已成长为行业学员质量好课程内容深企业满意的移动开发高端训练基地,并被评为中关村软件园重点扶持人才企业。黑马程序员的学员筛选制度,远比现在以上的企业招聘流程更为严格。系统的学习可以参考w3c的教程 web概念概述 * JavaWeb: * 使用Java语言开发基于互联网的项目 * 软件架构: 1. C/S: Client/Server 客户端/服务...

    Snailclimb 评论0 收藏0
  • Java入门请不要放弃,学习路线以及侧重点分析

    摘要:而面向搜索引擎,就是我们要及时的使用百度谷歌遇到问题无法解决,先别急着放弃,可以去网络寻找答案,你的坑大部分别人都已经走过了,大部分都可以找到合适的解决方案。 showImg(https://segmentfault.com/img/remote/1460000019236352?w=866&h=456); 前言: ●众多的语言,到底哪一门才是适合我的?●我们为什么要学习Java语言呢...

    mochixuan 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<