9.模板
//另一种思想叫泛型编程,主要利用模板
//提供两种模板机制:函数模板和类模板
//使用函数模板注意事项
//自动类型推导,必须推导出一致的T
//模板必须要确定出T的数据类型,才可以使用(函数体里不使用,除非显式指定类型)
//普通函数和函数模板区别:
// 普通函数调用时可以发生自动类型转换(隐式类型转换)
// 函数模板调用时,如果使用自动类型推导,不能发生隐式类型转换
// 如果使用显式指定类型,能发生隐式类型转换
//函数模板和普通函数调用规则:
// 如果两者都能实现,优先调用普通函数
// 可以通过空模板函数列表来强制调用函数模板
// 函数模板也可以重载
// 如果函数模板发生更好的匹配,优先调用函数模板
//模板的通用性不是万能的,有些特定的类型需要特定的实现
//在有myCompare(T a, T b)之后,无法比较两个自定义数据类型,可以利用具体化的Person的版本的代码实现,具体化优先调用
//template<> bool myCompare(Person a, Person b){具体比较Person类型的实现}
//类模板:建立一个通用类,类中成员的数据类型可以不具体制定,用一个虚拟类型代表
//类模板和函数模板区别
// 1.类模板没有自动类型推导的方式
// 2.类模板在模板参数列表中可以有默认参数
// template<class NameType, class AgeType = int>
//类模板中成员函数在调用时创建
//类模板函数作函数参数
// 1.指定传入类型
// 2.参数模板化
// 3.整个类模板化
//类模板与继承
// 1.当子类的父类是类模板时,子类在声明时,要指定出父类中T的类型
// 2.如果不指定,编译器无法分配内存
// 3.如果想灵活指出父类中T的类型,子类也需变为类模板
//类模板成员函数类外实现
//类模板成员函数分文件编写
// 1.包含.cpp文件
// 2.将.h和.cpp文件写到一起,改成.hpp文件
//类模板与友元
#include <iostream>
#include <string>
//类模板成员函数分文件编写
// 1.包含.cpp文件(实际很少这样去做)
//#include "person02.cpp"
// 2.将.h和.cpp文件写到一起,改成.hpp文件
#include "person02.hpp"
#include"my_array.hpp"
using namespace std;
//函数模板
template<typename T> //typename可以替换为class
void mySwap(T& a, T& b)
{
T tmp = a;
a = b;
b = tmp;
}
//通用数组排序
//规则:从大到小
//算法:选择排序
template<typename T>
void mySort(T& arr, int len)
{
for (int i = 0; i < len; i++)
{
int max = i;
for (int j = i + 1; j < len; j++)
{
if (arr[max] < arr[j])max = j;
}
if (max != i)
{
mySwap(arr[max], arr[i]);
}
}
}
template<typename T>
void printArray(T arr[], int len)
{
for (int i = 0;i < len;i++)
{
cout << arr[i] << " ";
}
cout << endl;
}
void test01()
{
//char数组
char charArr[] = "badcfe";
mySort(charArr, sizeof(charArr)/sizeof(char));
printArray(charArr, sizeof(charArr) / sizeof(char));
//int数组
int intArr[5] = { 4,3,2,1,5 };
mySort(intArr, sizeof(intArr) / sizeof(int));
printArray(intArr, sizeof(intArr) / sizeof(int));
}
//类模板
template<typename NameType, typename AgeType>
class Person
{
public:
Person(NameType name, AgeType age) :m_Age(age), m_Name(name) {}
void showPerson()
{
cout << "Name: " << this->m_Name << " Age:" << this->m_Age << endl;
}
NameType m_Name;
AgeType m_Age;
};
void test02()
{
Person<string, int> p1("张三", 18);
p1.showPerson();
}
//类模板对象作函数参数
template <class T1, class T2>
class Member
{
public:
T1 m_Name;
T2 m_Age;
Member(T1 name, T2 age) :m_Name(name), m_Age(age) {}
void showMember()
{
cout << "姓名:" << this->m_Name << " 年龄:" << this->m_Age << endl;
}
};
void func1(Member<string,int>& m)
{
//1.指定传入类型
m.showMember();
}
template <typename T1, typename T2>
void func2(Member<T1,T2> m)
{
//2.参数模板化
m.showMember();
cout << "T1的类型为" << typeid(T1).name() << endl;
cout << "T2的类型为" << typeid(T2).name() << endl;
}
template <typename T>
void func3(T m)
{
//3.整个类模板化
m.showMember();
}
void test03()
{
Member<string, int> m("张三", 18);
func1(m);
func2(m);
func3(m);
}
//类模板成员函数类外实现
template<class T1, class T2>
class Person01
{
public:
Person01(T1 name, T2 age);
void showPerson();
T1 m_Name;
T2 m_Age;
};
template<class T1, class T2>
Person01<T1,T2>::Person01(T1 name, T2 age)
{
this->m_Name = name;
this->m_Age = age;
}
template<class T1, class T2>
void Person01<T1, T2>::showPerson()
{
cout << "姓名:" << m_Name << " 年龄:" << m_Age << endl;
}
//template<class T1, class T2>
//class Person02
//{
//public:
// Person02(T1 name, T2 age);
// void showPerson();
// T1 m_Name;
// T2 m_Age;
//};
//template<class T1, class T2>
//Person02<T1, T2>::Person02(T1 name, T2 age)
//{
// this->m_Name = name;
// this->m_Age = age;
//}
//
//template<class T1, class T2>
//void Person02<T1, T2>::showPerson()
//{
// cout << "姓名:" << m_Name << " 年龄:" << m_Age << endl;
//}
void test04()
{
Person02<string, int> p("张三", 18);
p.showPerson();
}
//之前要告知编译器时模板类
template<class T1, class T2>
class Person03;
//全局函数类外实现
//上方时普通函数的声明,下方是函数模板的实现
template<class T1, class T2>
void printPerson(Person03<T1, T2> p)
{
cout << "Name: " << p.m_Name << " Age: " << p.m_Age << endl;
}
//类模板与友元
template<class T1, class T2>
class Person03
{
// 全局函数类内实现
//friend void printPerson(Person03<T1, T2> p)
//{
// cout << "Name: " << p.m_Name << " Age: " << p.m_Age << endl;
//}
//全局函数类外实现
//加空模板参数列表
//如果全局函数时类外实现,需要让编译器提前知道这个函数的存在
friend void printPerson<>(Person03<T1, T2> p);
public:
Person03(T1 name, T2 age) :m_Name(name), m_Age(age) {}
private:
T1 m_Name;
T2 m_Age;
};
void test05()
{
Person03<string, int> p("Tom", 20);
printPerson(p);
}
void printIntArray(MyArray<int>& arr)
{
for (int i = 0;i < arr.getSize();i++)
{
cout << arr[i] << endl;
}
}
//类模板案例
void test06()
{
MyArray<int> arr1(5);
//MyArray<int> arr2(arr1);
//MyArray<int> arr3(3);
//arr3 = arr1;
for (int i = 0;i < 5;i++)
{
arr1.pushBack(i);
}
printIntArray(arr1);
cout << "arr1_capacity: " << arr1.getCapacity() << " arr1_size: " << arr1.getSize() << endl;
MyArray<int> arr2(arr1);
printIntArray(arr2);
arr2.popBack();
printIntArray(arr2);
cout << "arr2_capacity: " << arr2.getCapacity() << " arr2_size: " << arr2.getSize() << endl;
}
int main()
{
//int a = 10, b = 20;
////两种使用方式
////1.自动类型推导
//myswap(a, b);
//cout << "a = " << a << endl;
//cout << "b = " << b << endl;
////2.显示指定类型
//myswap<int>(a, b);
//cout << "a = " << a << endl;
//cout << "b = " << b << endl;
test06();
system("pause");
return 0;
}
//另一种思想叫泛型编程,主要利用模板
//提供两种模板机制:函数模板和类模板
//使用函数模板注意事项
//自动类型推导,必须推导出一致的T
//模板必须要确定出T的数据类型,才可以使用(函数体里不使用,除非显式指定类型)
//普通函数和函数模板区别:
// 普通函数调用时可以发生自动类型转换(隐式类型转换)
// 函数模板调用时,如果使用自动类型推导,不能发生隐式类型转换
// 如果使用显式指定类型,能发生隐式类型转换
//函数模板和普通函数调用规则:
// 如果两者都能实现,优先调用普通函数
// 可以通过空模板函数列表来强制调用函数模板
// 函数模板也可以重载
// 如果函数模板发生更好的匹配,优先调用函数模板
//模板的通用性不是万能的,有些特定的类型需要特定的实现
//在有myCompare(T a, T b)之后,无法比较两个自定义数据类型,可以利用具体化的Person的版本的代码实现,具体化优先调用
//template<> bool myCompare(Person a, Person b){具体比较Person类型的实现}
//类模板:建立一个通用类,类中成员的数据类型可以不具体制定,用一个虚拟类型代表
//类模板和函数模板区别
// 1.类模板没有自动类型推导的方式
// 2.类模板在模板参数列表中可以有默认参数
// template<class NameType, class AgeType = int>
//类模板中成员函数在调用时创建
//类模板函数作函数参数
// 1.指定传入类型
// 2.参数模板化
// 3.整个类模板化
//类模板与继承
// 1.当子类的父类是类模板时,子类在声明时,要指定出父类中T的类型
// 2.如果不指定,编译器无法分配内存
// 3.如果想灵活指出父类中T的类型,子类也需变为类模板
//类模板成员函数类外实现
//类模板成员函数分文件编写
// 1.包含.cpp文件
// 2.将.h和.cpp文件写到一起,改成.hpp文件
//类模板与友元
#include <iostream>
#include <string>
//类模板成员函数分文件编写
// 1.包含.cpp文件(实际很少这样去做)
//#include "person02.cpp"
// 2.将.h和.cpp文件写到一起,改成.hpp文件
#include "person02.hpp"
#include"my_array.hpp"
using namespace std;
//函数模板
template<typename T> //typename可以替换为class
void mySwap(T& a, T& b)
{
T tmp = a;
a = b;
b = tmp;
}
//通用数组排序
//规则:从大到小
//算法:选择排序
template<typename T>
void mySort(T& arr, int len)
{
for (int i = 0; i < len; i++)
{
int max = i;
for (int j = i + 1; j < len; j++)
{
if (arr[max] < arr[j])max = j;
}
if (max != i)
{
mySwap(arr[max], arr[i]);
}
}
}
template<typename T>
void printArray(T arr[], int len)
{
for (int i = 0;i < len;i++)
{
cout << arr[i] << " ";
}
cout << endl;
}
void test01()
{
//char数组
char charArr[] = "badcfe";
mySort(charArr, sizeof(charArr)/sizeof(char));
printArray(charArr, sizeof(charArr) / sizeof(char));
//int数组
int intArr[5] = { 4,3,2,1,5 };
mySort(intArr, sizeof(intArr) / sizeof(int));
printArray(intArr, sizeof(intArr) / sizeof(int));
}
//类模板
template<typename NameType, typename AgeType>
class Person
{
public:
Person(NameType name, AgeType age) :m_Age(age), m_Name(name) {}
void showPerson()
{
cout << "Name: " << this->m_Name << " Age:" << this->m_Age << endl;
}
NameType m_Name;
AgeType m_Age;
};
void test02()
{
Person<string, int> p1("张三", 18);
p1.showPerson();
}
//类模板对象作函数参数
template <class T1, class T2>
class Member
{
public:
T1 m_Name;
T2 m_Age;
Member(T1 name, T2 age) :m_Name(name), m_Age(age) {}
void showMember()
{
cout << "姓名:" << this->m_Name << " 年龄:" << this->m_Age << endl;
}
};
void func1(Member<string,int>& m)
{
//1.指定传入类型
m.showMember();
}
template <typename T1, typename T2>
void func2(Member<T1,T2> m)
{
//2.参数模板化
m.showMember();
cout << "T1的类型为" << typeid(T1).name() << endl;
cout << "T2的类型为" << typeid(T2).name() << endl;
}
template <typename T>
void func3(T m)
{
//3.整个类模板化
m.showMember();
}
void test03()
{
Member<string, int> m("张三", 18);
func1(m);
func2(m);
func3(m);
}
//类模板成员函数类外实现
template<class T1, class T2>
class Person01
{
public:
Person01(T1 name, T2 age);
void showPerson();
T1 m_Name;
T2 m_Age;
};
template<class T1, class T2>
Person01<T1,T2>::Person01(T1 name, T2 age)
{
this->m_Name = name;
this->m_Age = age;
}
template<class T1, class T2>
void Person01<T1, T2>::showPerson()
{
cout << "姓名:" << m_Name << " 年龄:" << m_Age << endl;
}
//template<class T1, class T2>
//class Person02
//{
//public:
// Person02(T1 name, T2 age);
// void showPerson();
// T1 m_Name;
// T2 m_Age;
//};
//template<class T1, class T2>
//Person02<T1, T2>::Person02(T1 name, T2 age)
//{
// this->m_Name = name;
// this->m_Age = age;
//}
//
//template<class T1, class T2>
//void Person02<T1, T2>::showPerson()
//{
// cout << "姓名:" << m_Name << " 年龄:" << m_Age << endl;
//}
void test04()
{
Person02<string, int> p("张三", 18);
p.showPerson();
}
//之前要告知编译器时模板类
template<class T1, class T2>
class Person03;
//全局函数类外实现
//上方时普通函数的声明,下方是函数模板的实现
template<class T1, class T2>
void printPerson(Person03<T1, T2> p)
{
cout << "Name: " << p.m_Name << " Age: " << p.m_Age << endl;
}
//类模板与友元
template<class T1, class T2>
class Person03
{
// 全局函数类内实现
//friend void printPerson(Person03<T1, T2> p)
//{
// cout << "Name: " << p.m_Name << " Age: " << p.m_Age << endl;
//}
//全局函数类外实现
//加空模板参数列表
//如果全局函数时类外实现,需要让编译器提前知道这个函数的存在
friend void printPerson<>(Person03<T1, T2> p);
public:
Person03(T1 name, T2 age) :m_Name(name), m_Age(age) {}
private:
T1 m_Name;
T2 m_Age;
};
void test05()
{
Person03<string, int> p("Tom", 20);
printPerson(p);
}
void printIntArray(MyArray<int>& arr)
{
for (int i = 0;i < arr.getSize();i++)
{
cout << arr[i] << endl;
}
}
//类模板案例
void test06()
{
MyArray<int> arr1(5);
//MyArray<int> arr2(arr1);
//MyArray<int> arr3(3);
//arr3 = arr1;
for (int i = 0;i < 5;i++)
{
arr1.pushBack(i);
}
printIntArray(arr1);
cout << "arr1_capacity: " << arr1.getCapacity() << " arr1_size: " << arr1.getSize() << endl;
MyArray<int> arr2(arr1);
printIntArray(arr2);
arr2.popBack();
printIntArray(arr2);
cout << "arr2_capacity: " << arr2.getCapacity() << " arr2_size: " << arr2.getSize() << endl;
}
int main()
{
//int a = 10, b = 20;
////两种使用方式
////1.自动类型推导
//myswap(a, b);
//cout << "a = " << a << endl;
//cout << "b = " << b << endl;
////2.显示指定类型
//myswap<int>(a, b);
//cout << "a = " << a << endl;
//cout << "b = " << b << endl;
test06();
system("pause");
return 0;
}
my_array.hpp
#pragma once
#include<iostream>
using namespace std;
template <class T>
class MyArray
{
public:
MyArray(int capacity) :m_capacity(capacity), m_size(0), pAddress(new T[capacity]) { cout << "MyArray的有参构造" << endl; }
MyArray(const MyArray& arr)
{
cout << "MyArray的拷贝构造" << endl;
this->m_capacity = arr.m_capacity;
this->m_size = arr.m_size;
//深拷贝
this->pAddress = new T[arr.m_capacity];
//拷贝arr中的数据
for (int i = 0; i < this->m_size;i++)
{
this->pAddress[i] = arr.pAddress[i];
}
}
MyArray& operator=(MyArray& arr)
{
cout << "MyArray的operator=重载" << endl;
//先判断原来堆区是否有数据,如果有,需要释放
if (this->pAddress != nullptr)
{
delete[] this->pAddress;
this->pAddress = nullptr;
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];
//拷贝arr中的数据
for (int i = 0; i < this->m_size;i++)
{
this->pAddress[i] = arr.pAddress[i];
}
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 != nullptr)
{
cout << "MyArray的析构函数" << endl;
delete[] this->pAddress;
this->pAddress = nullptr;
}
}
private:
T* pAddress;
int m_capacity;
int m_size;
};
person02.h
#pragma once
#include<iostream>
using namespace std;
template<class T1, class T2>
class Person02
{
public:
Person02(T1 name, T2 age);
void showPerson();
T1 m_Name;
T2 m_Age;
};
person02.cpp
#include"person02.h"
template<class T1, class T2>
Person02<T1, T2>::Person02(T1 name, T2 age)
{
this->m_Name = name;
this->m_Age = age;
}
template<class T1, class T2>
void Person02<T1, T2>::showPerson()
{
cout << "姓名:" << m_Name << " 年龄:" << m_Age << endl;
}
person02.hpp
#pragma once
#include<iostream>
using namespace std;
template<class T1, class T2>
class Person02
{
public:
Person02(T1 name, T2 age);
void showPerson();
T1 m_Name;
T2 m_Age;
};
template<class T1, class T2>
Person02<T1, T2>::Person02(T1 name, T2 age)
{
this->m_Name = name;
this->m_Age = age;
}
template<class T1, class T2>
void Person02<T1, T2>::showPerson()
{
cout << "姓名:" << m_Name << " 年龄:" << m_Age << endl;
}