一、模板
3、类模板
类模板作用:建立一个通用的类,类中的成员数据类型可以不具体定制,用一个虚拟的类型来代表。
1)语法:
template
类
3)类模板和函数模板的区别
主要有两点:
(1)类模板没有自动推导的使用方式
(2)类模板在模板参数列表中可以有默认参数
4)类模板中成员函数创建时机
类模板中成员函数和普通类中成员函数创建时间是有区别的:
普通类中的成员函数一开始就创建了。而类模板中的成员函数调用时才创建
5)类模板作函数参数
类模板实例化出来的对象向函数传参的方式(3种)
(1)指定传入的类型---直接显示对象的数据类型(常用)
(2)参数模板化---将对象中的参数变为模板进行传递
查看参数的类型
(3)整个类模板化---将这个对象类型模板化进行传递
6)类模板与继承
当类模板碰到继承时,应注意:
(1)当子类继承的父类是一个类模板时,子类在声明时要指定父类中T的类型
(2)如果不指定,编译器无法给子类分配内存
(3)如果想灵活指定出父类中T的类型,子类也需要变为类模板
7)类模板成员函数的类外实现
8)类模板的分文件的编写
问题:类模板中成员函数创建时机是在调用阶段,导致分文件编写时链接不到
解决:
方式1:直接包含.cpp文件
方式2:将声明和实现写到同一个文件中,并更名为.hpp,.hpp是约定的名称 并不是强制。
9)类模板与友元
全局函数类内实现:直接在类内声明友元即可。
全局函数类外实现:需要提前让编译器知道全局函数的存在。
10)模板案例:写一个通用数组类 实现以下功能:
1、可以对内置数据类型以及自定义数据类型进行存储
2、将数组中数据存放到堆区
3、构造函数中可以传入数组的容量
4、提供对应的拷贝构造函数以及operator=防止浅拷贝问题
5、尾插法、尾删法
6、通过下标方式访问数组元素
7、可获取数组中当前元素个数以及数组容量
代码:
.hpp文件
//自己的通用数组类 #pragma once #includeusing namespace std; #include template class MyArray { private: T * pAddress;//将数据放在堆中 int m_Capacity; int size; public: MyArray(int capacity) { cout << "MyArray有参构造调用" << endl; this->m_Capacity = capacity; this->size = 0; this->pAddress = new T[this->m_Capacity]; } //拷贝构造 MyArray(const MyArray& arr) { cout << "MyArray拷贝构造调用" << endl; this->m_Capacity = arr.m_Capacity; this->size = arr.size; //this->pAddress = arr.pAddress 在堆区的数据不能直接这样复制 //深拷贝 this->pAddress = new T[arr.m_Capacity]; for (int i = 0; i < arr.size; i++) { this->pAddress[i] = arr.pAddress[i]; } } //重载= 防止浅拷贝 a=b=c时b、c值为空的情况 MyArray& operator=(const MyArray& arr) { cout << "MyArray operator=重载调用" << endl; //先判断堆区是否有数据 有则先释放 if (this->pAddress != NULL) { delete[] this->pAddress; this->pAddress = NULL; this->m_Capacity = 0; this->size = 0; } //深拷贝 this->m_Capacity = arr.m_Capacity; this->size = arr.size; this->pAddress = new T[this->m_Capacity]; for (int i = 0; i < arr.size; i++) { this->pAddress[i] = arr.pAddress[i]; } return *this; } //尾插法: void Push_Back(const T &val) { //判断容量是否已满 if (this->size == this->m_Capacity) { cout << "容量已满,无法插入!" << endl; return; } this->pAddress[this->size] = val; size++; } //尾删法 void Pop_Back() { //让用户访问不到最后一个元素 即逻辑尾删 if (this->size == 0) { cout << "无元素" << endl; return; } this->size--; } //通过下标的方式访问数组中元素 重载[]符号 注意若要最终返回的元素可以以arr[0]=100 的方式 则需要加& T& operator[](int index) { return this->pAddress[index]; } //返回数组容量 int get_Capacity() { return this->m_Capacity; } //返回数组大小 int get_Size() { return this->size; } //析构 ~MyArray() { cout << "MyArray析构调用" << endl; if (this->pAddress != nullptr) { delete [] this->pAddress; this->pAddress = NULL; } } };
.cpp文件
//实现一个通用的数组类 #include "MyArray.hpp" void PrintArray(MyArray&arr); void test01() { MyArray M(5); //MyArray arr1(M);//测试拷贝构造函数 //MyArray arr2(100); //arr2 = arr1;//测试=重载 for (int i = 0; i < 5; i++) { M.Push_Back(i); } cout << "M[3]:" << M.operator[](3) << endl; PrintArray(M); cout << "M的容量:" << M.get_Capacity() << endl; cout << "M的大小:" << M.get_Size() << endl; MyArray M1(M); PrintArray(M1); cout << "M1的容量:" << M1.get_Capacity() << endl; cout << "M1的大小:" << M1.get_Size() << endl; cout << "尾删后" << endl; M1.Pop_Back(); cout << "M1的容量:" << M1.get_Capacity() << endl; cout << "M1的大小:" << M1.get_Size() << endl; } void PrintArray(MyArray &arr) { for (int i = 0; im_age = age; this->m_name = name; } }; void PrintPerson(MyArray arr) { for (int i = 0; i < arr.get_Size(); i++) { cout << "姓名:" << arr[i].m_name << " 年龄:" << arr[i].m_age << endl; } } void test02() { MyArray arr(10); Person p1("张三",18); Person p2("李四",30); Person p3("王五",19); Person p4("赵六",28); Person p5("郑七",27); Person p6("孙八",19); Person p7("吴九",38); Person p8("胡十",28); cout << "没插入前容量:" << arr.get_Capacity() << " 大小为:" << arr.get_Size() << endl; arr.Push_Back(p1); arr.Push_Back(p2); arr.Push_Back(p3); arr.Push_Back(p4); arr.Push_Back(p5); arr.Push_Back(p6); arr.Push_Back(p7); arr.Push_Back(p8); cout << "插入后容量:" << arr.get_Capacity() << " 大小为:" << arr.get_Size() << endl; PrintPerson(arr); } int main() { test01(); test02(); return 0; }
运行结果:



