目录

1 模板

01 模板的概念

02 函数模板基本语法

03 函数模板注意事项

04 函数模板案例-数组排序

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

06 普通函数与函数模板调用规则

07 模板的局限性

08 类模板基本语法

09 类模板与函数模板区别

10 类模板中成员函数创建时机

11 类模板对象做函数参数

12 类模板与继承

13 类模板成员函数类外实现

14 类模板分文件编写

15 类模板与友元

16 类模板案例-数组类封装

2 STL初识

19 STL的基本概念

20 vector存放内置数据类型

21 vector存放自定义数据类型

22 容器嵌套容器


1 模板

01 模板的概念

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

特点:不可以直接使用,只是一个框架;通用并不是万能

02 函数模板基本语法

目的是为了提高函数复用性,函数模板将类型参数化

使用模板有两种方式:自动类型推导、显示指定类型

template<typename T>
void mySwap(T& a, T& b)
{T temp = a;a = b;b = temp;
}void test01()
{int a = 10;int b = 20;//两种方式使用函数模板//1.自动类型推导//mySwap(a, b);//2.显示指定类型mySwap<int>(a, b);cout << "a=" << a << endl;//20cout << "b=" << b << endl;//10
}

03 函数模板注意事项

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

04 函数模板案例-数组排序

//实现通用 对数组进行排序的函数

template <class T>
void mySwap(T &a, T &b)
{int temp = a;a= b;b = temp;
}template <class T>
void mySort(T arr[],int len)//选择排序,从大到小
{for (int i = 0; i < len; i++){int max = i;int j = 0;for (int j = i + 1; j < len; j++){if (arr[j] > arr[max]){max = j;}}if (max != j){mySwap(arr[max], arr[i]);}}
}template <class T>
void printArray(T arr[], int len)
{for (int i = 0; i < len; i++){cout << arr[i]<<" ";}cout << endl;
}void test01()
{char charArr[] = { 's','k','y','e' };int num = sizeof(charArr) / sizeof(char);mySort(charArr, num);printArray(charArr, num);
}void test02()
{int intArr[] = { 1,2,3,3,3,2,4,4,5,43,1,2,2 };int num = sizeof(intArr) / sizeof(int);mySort(intArr, num);printArray(intArr, num);
}int main()
{test01();//y s k etest02();//43 5 4 4 3 3 3 2 2 2 2 1 1system("pause");return 0;
}

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

06 普通函数与函数模板调用规则

 myPrint<>(a, b);//空模板参数列表强制调用函数模板

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

07 模板的局限性

模板的通用性并不是万能的

提供了模板的重载,可以为这些特定的类型提供具体化的模板,解决自定义类型的通用化

//template<>

class Person
{
public:Person(string name, int age){this->m_Name = name;this->m_Age = age;}string m_Name;int m_Age;
};
template <class T>
bool myCompare(T& a, T& b)
{if (a == b){return true;}else{return false;}
}
//利用具体化Person的版本实现代码,具体化优先调用
template<>bool myCompare(Person& p1, Person& p2)
{if (p1.m_Name == p2.m_Name && p1.m_Age == p2.m_Age){return true;}else{return false;}
}void test02()
{Person p1("Tom", 10);Person p2("Tom", 20);bool ret = myCompare(p1, p2);if (ret){cout << "p1==p2" << endl;}else{cout << "p1!=p2" << endl;}
}

08 类模板基本语法

template <class NameType,class AgeType>
class Person
{
public:Person(NameType name, AgeType age){this->m_Name = name;this->m_Age = age;}void showPerson(){cout << "name:" << this->m_Name << "age:" << this->m_Age << endl;}NameType m_Name;AgeType m_Age;
};int main()
{Person<string, int>p1("孙悟空", 999);p1.showPerson();//name:孙悟空age:999return 0;
}

09 类模板与函数模板区别

1.类模板没有自动类型推导的使用方式

Person<string, int>p1("sunwukong", 999);//只能用显示指定类型

2.类模板在模板参数列表中可以有默认参数

template<class NameType,class AgeType=int>
Person<string>p1("sunwukong", 999);

10 类模板中成员函数创建时机

类模板中成员函数和普通类中成员函数创建时机是有区别的:

普通类中的成员函数一开始就可以创建

类模板中的成员函数在调用时才可以创建

11 类模板对象做函数参数

指定传入的类型最常用

template<class T1,class T2>
class Person
{
public:Person(T1 name, T2 age){this->m_Name = name;this->m_Age = age;}void showPerson(){cout << "姓名:" << this->m_Name << "年龄:" << this->m_Age << endl;}T2 m_Age;T1 m_Name;
};//1.指定传入类型
void printPerson(Person<string, int>& p)
{p.showPerson();
}
//2.参数模板化
template<class T1,class T2>
void printPerson2(Person<T1,T2>& p)
{p.showPerson();cout << "T1的类型为:" << typeid(T1).name() << endl;cout << "T2的类型为:" << typeid(T2).name() << endl; /*姓名:zbj年龄:1000T1的类型为:class std::basic_string<char, struct std::char_traits<char>, class std::allocator<char> >T2的类型为:int*/
}
//3.整个类模板化
template<class T>
void printPerson3(T &p)
{p.showPerson();//姓名:ts年龄:500cout << "T的类型为:" << typeid(T).name() << endl;//T的类型为:class Person<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,int>
}void test01()
{Person<string, int>p("swk", 100);printPerson(p);
}
void test02()
{Person<string, int>p("zbj", 1000);printPerson2(p);
}
void test03()
{Person<string, int>p("ts", 500);printPerson3(p);
}
//1
void printPerson(Person<string, int>& p)
//2
template<class T1,class T2>
void printPerson2(Person<T1,T2>&p)
{}
//3
template<class T>
void printPerson3(T &p)
{}

12 类模板与继承

总结:如果父类是模板,子类需要指定出父类中T的数据类型

template <class T>
class Base
{T m;
};//class Son :public Base//错误,需要指定出父类中T的数据类型
class Son :public Base<int>
{};
//如果想灵活指定父类中T类型,子类也需要变成类模板
template <class T2, class T>
class Son2 :public Base<T>
{
public:Son2(){cout << "T2类型为:" << typeid(T2).name() << endl;cout << "T类型为:" << typeid(T).name() << endl;}T2 obj;
};void test()
{Son2<int, char>s2;//T2类型为:int//T类型为:char
}

13 类模板成员函数类外实现

template<class NameType, class AgeType>
class Person
{
public:Person(NameType name, AgeType age);//声明void showPerson();NameType m_Name;AgeType m_Age;
};
//构造函数类外实现
template<class NameType, class AgeType>
Person<NameType, AgeType>::Person(NameType name, AgeType age)
{this->m_Age = age;this->m_Name = name;
}
//成员函数类外实现
template<class NameType, class AgeType>
void Person<NameType, AgeType>::showPerson()
{cout << "name:" << this->m_Name << endl;cout << "age:" << this->m_Age << endl;
}

14 类模板分文件编写

15 类模板与友元

类模板配合友元函数的类内实现和类外实现:

  • 全局函数类内实现——直接在类内声明友元即可
  • 全局函数类外实现——需要提前让编译器知道全局函数存在

建议全局函数做类内实现 

//通过全局函数 打印Person信息//提前让编译器知道Person类存在
template<class T1, class T2>
class Person;
//全局函数 类外实现——提前让编译器知道printPerson2存在
template<class T1, class T2>
void printPerson2(Person<T1, T2> p)
{cout << "类外——姓名:" << p.m_Name << "年龄:" << p.m_Age << endl;
}template<class T1, class T2>
class Person
{//全局函数 类内实现friend void printPerson(Person<T1, T2> p){cout << "姓名:" << p.m_Name << "年龄:" << p.m_Age << endl;}//全局函数 类外实现//1.需要加空模板参数列表//2.如果全局函数是类外实现,需要让编译器提前知道有这个模板存在friend void printPerson2<>(Person<T1, T2> p);
public:Person(T1 name, T2 age){this->m_Name = name;this->m_Age = age;}
private:T1 m_Name;T2 m_Age;
};void test01()
{Person<string, int>p("TOM", 20);printPerson(p);// 姓名:TOM年龄:20printPerson2(p);//类外——姓名:TOM年龄:20
}

16 类模板案例-数组类封装

//自己通用的数组类myArray.hpp

template <class T>
class MyArray
{
public://有参构造MyArray(int capacity){this->m_Capacity = capacity;this->m_Size = 0;this->pAddress = new T[this->m_Capacity];cout << "有参构造" << endl;}//拷贝构造MyArray(const MyArray& arr){this->m_Capacity = arr.m_Capacity;this->m_Size = arr.m_Size;this->pAddress=new T[arr.m_Capacity];//深拷贝for (int i = 0; i < this->m_Size; i++){this->pAddress[i] = arr.pAddress[i];}cout << "拷贝构造" << endl;}//operator=防止浅拷贝问题MyArray& operator=(const MyArray& arr){//先判断原来堆区是否有数据if (this->pAddress != NULL){delete[]this->pAddress;this->pAddress = NULL;this->m_Capacity = 0;this->m_Size = 0;}//深拷贝this->m_Capacity = arr.m_Capacity;this->m_Size = arr.m_Size;this->pAddress = new T[arr.m_Capacity];for (int i = 0; i < this->m_Size; i++){this->pAddress[i] = arr.pAddress[i];}cout << "operator=" << endl;return *this;}//尾插法void PushBack(const T & val){if (this->m_Capacity == this->m_Size){return;}this->pAddress[this->m_Size] = val;this->m_Size++;}//尾删法void PopBack(){//访问不到最后一个if (this->m_Size == 0){return;}this->m_Size--;}//通过下标方式访问数组中的元素T& operator[](int index){return this->pAddress[index];}//返回数组容量 和大小int getCapacity(){return this->m_Capacity;}int getSize(){return this->m_Size;}//析构函数~MyArray(){if (this->pAddress != NULL){delete[]this->pAddress;this->pAddress = NULL;}cout << "析构函数" << endl;}
private:T* pAddress;//指针指向堆区开辟的数组int m_Capacity;//容量int m_Size;//大小
};

2 STL初识

19 STL的基本概念

20 vector存放内置数据类型

#include <vector>
#include<algorithm>void myPrint(int val)
{cout << "3 ";cout << "val" << endl;
}void test01()
{//创建vector容器,数组vector<int>v;//向容器插入数据v.push_back(10);v.push_back(20);v.push_back(30);//通过迭代器访问容器中的数据//v.begin()起始迭代器 指向容器中第一个元素//v.end()结束迭代器 指向容器中最后一个元素的下一个位置vector<int>::iterator itBegin = v.begin();vector<int>::iterator itEnd = v.end();//第一种遍历方式while (itBegin != itEnd){cout << "1 ";cout << *itBegin << endl;itBegin++;}//第二种遍历方式for (vector<int>::iterator it = v.begin(); it != v.end(); it++){cout << "2 ";cout << *it << endl;}//第三种遍历 利用STL提供的遍历算法for_each(v.begin(), v.end(), myPrint);FUNCTION TEMPLATE for_each//template <class _InIt, class _Fn>//_CONSTEXPR20 _Fn for_each(_InIt _First, _InIt _Last, _Fn _Func) { // perform function for each element [_First, _Last)//   _Adl_verify_range(_First, _Last);// auto _UFirst = _Get_unwrapped(_First);//   const auto _ULast = _Get_unwrapped(_Last);//   for (; _UFirst != _ULast; ++_UFirst) {//     _Func(*_UFirst);//  }
}

21 vector存放自定义数据类型

class Person
{
public:Person(string name, int age){this->m_name = name;this->m_age = age;}string m_name;int m_age;
};void test02()
{vector<Person>v;Person p1("asd", 10);Person p2("sf", 20);Person p3("sdf", 30);v.push_back(p1);v.push_back(p2);v.push_back(p3);for (vector<Person>::iterator it = v.begin(); it != v.end(); it++){cout << "姓名:" << (*it).m_name << " " << "年龄:" << it->m_age << endl;}
}void test03()
{vector<Person*>v;Person p1("asd", 10);Person p2("sf", 20);Person p3("sdf", 30);v.push_back(&p1);v.push_back(&p2);v.push_back(&p3);for (vector<Person*>::iterator it = v.begin(); it != v.end(); it++){cout << "姓名:" << (*it)->m_name << " " << "年龄:" << (*(*it)).m_age << endl;}
}

22 容器嵌套容器

void test01()
{//创建vector容器,二维数组vector<vector<int>>v;//创建小容器vector<int>v1;vector<int>v2;vector<int>v3;for (int i = 0; i < 4; i++){//向小容器中插入数据v1.push_back(i + 1);v2.push_back(i + 2);v3.push_back(i + 3);}//将小容器插入大容器中v.push_back(v1);v.push_back(v2);v.push_back(v3);//通过迭代器访问大容器中的数据for (vector<vector<int>>::iterator it = v.begin(); it != v.end(); it++){//(*it)<==>容器vector<int>for (vector<int>::iterator vit = (*it).begin(); vit != (*it).end(); vit++){cout << *vit << " ";}cout << endl;}
}

笔记 黑马程序员C++教程从0到1入门编程——提高编程01相关推荐

  1. 笔记 黑马程序员C++教程从0到1入门编程——基础语法入门

    目录 1.C++初识 02 C++书写helloworld 03 注释 04 变量 05 常量 06 关键字 07 标识符命名规则 2.数据类型 08 整型 09 sizeof关键字 10 实型(浮点 ...

  2. 笔记 黑马程序员C++教程从0到1入门编程——提高编程02

    目录 3 STL-常用容器 string容器 189 构造函数 190 赋值操作 191 字符串拼接 192 字符串查找和替换 193 字符串比较 194 字符存取 195 字符串插入和删除 196 ...

  3. 笔记 黑马程序员C++教程从0到1入门编程——提高编程03

    目录 4 STL-函数对象 237 函数对象 谓词 238 一元谓词 239 二元谓词 内建函数对象 240 算术仿函数 241 关系仿函数 242 逻辑仿函数 5 STL-常用算法 遍历算法 243 ...

  4. 【黑马程序员 C++教程从0到1入门编程】【笔记4】C++核心编程(类和对象——封装、权限、对象的初始化和清理、构造函数、析构函数、深拷贝、浅拷贝、初始化列表、友元friend、运算符重载)

    黑马程序员C++教程 文章目录 4 类和对象(类属性[成员属性],类函数[成员函数]) 4.1 封装 4.1.1 封装的意义(三种权限:public公共.protected保护.private私有)( ...

  5. 【黑马程序员 C++教程从0到1入门编程】【笔记3】C++核心编程(内存分区模型、引用、函数提高)

    黑马程序员匠心之作|C++教程从0到1入门编程,学习编程不再难 文章目录 1 内存分区模型 1.1 程序运行前 1.2 程序运行后(手动开辟内存:c语言malloc,c++new) 1.3 new操作 ...

  6. 【黑马程序员 C++教程从0到1入门编程】【笔记2】通讯录管理系统

    黑马程序员匠心之作|C++教程从0到1入门编程,学习编程不再难 文章目录 1.系统需求 2.创建项目 2.1 创建项目 3.菜单功能 4.退出功能 5.添加联系人 5.1 设计联系人结构体 5.2 设 ...

  7. 【黑马程序员 C++教程从0到1入门编程】【笔记1】数据类型、运算符、程序流程结构、数组、函数、指针、结构体

    黑马程序员匠心之作|C++教程从0到1入门编程,学习编程不再难 文章目录 1.C++初识 1.1 第一个c++程序 1.2 注释 1.3 变量 1.4 常量 1.5 关键字 1.6 标识符命名规则 2 ...

  8. 【C++】黑马程序员 | c++教程从0到1入门编程笔记 | c++提高编程

    配套视频:https://www.bilibili.com/video/BV1et411b73Z 文章目录: 一.C++核心编程 二.C++提高编程 1 模板 本阶段主要针对C++泛型编程和STL技术 ...

  9. 【黑马程序员 C++教程从0到1入门编程】【笔记6】C++核心编程(文件操作)

    文章目录 5 文件操作 5.1文本文件 5.1.1写文件 5.1.2读文件 5.2 二进制文件 5.2.1 写文件(用二进制方式写时最好别用c++的string) 5.2.2 读文件 https:// ...

最新文章

  1. 运用家居收纳储物空间 小空间变出大身材
  2. 让你省写大量重复代码的方法 使用PropertyInfo类 反射获取类 的类型 .
  3. 我的vscode配置 利用Settings Sync一键安装
  4. 二十二、标志寄存器与栈(代码设计安全,与子程序寄存器安全类似)
  5. 【bzoj4321】queue2 dp
  6. Azure角色管理技巧和工具
  7. Android BUG调试相关方法整理
  8. Java编译出现不可映射字符
  9. 对数(log)的换算公式
  10. java fup spring
  11. w ndows 10关机快捷键,win10系统
  12. 各种音视频编解码学习详解之 编解码学习笔记(九):QuickTime系列
  13. 使用matlab在图片上画框,并保存
  14. 有能干到退休的程序员吗?
  15. HDU-2094(产生冠军)
  16. Linux 内核编程风格
  17. WebJars简介 —— 前端资源的jar包形式
  18. 计算机网络——IP地址的作用
  19. 蓝鲸社区版单机、多机部署踩坑分享
  20. linux系统安装tv软件下载,linux怎么安装teamviewer|TV

热门文章

  1. Vue3学习之旅--Vue3高级语法补充-自定义指令,vue插件,Teleport......
  2. 文件共享服务器如何提高网速,怎么提高网速 提高网速方法【详细介绍】
  3. MySQL5.7(Linux)创建表报错:“Row size too large (> 8126). Changing some columns to TEXT or BLOB may help.”
  4. Android 7.0 Audio的Resample过程详解
  5. 微软裁员人工智能伦理和社会团队
  6. android 视频通话开启呼叫等待后,来第三方的视频通话,接通后通话时间一直显示为0,过几秒之后视频通话自动挂断
  7. ajax同时调用两个jsonp,使用JSONP进行跨域Ajax 调用
  8. 一篇SEO指南:新手如何从零开始优化自己的网站
  9. 微信拼手气红包C语言,微信拼手气红包算法分析
  10. 经纬财富:鄂尔多斯套单形成的表现与解套技巧