1. 模板
1.1 知识点
模板:template
泛型编程:
是指数据的类型是广泛,任意的数据类型
模板:可以将一个函数或类描述成一个模板,例如:画画,给一个人物模型上色彩,根据用户上的色彩是什么人物显示什么样的色彩
模板分为 函数模板 和 类模板
1.1.1 注意
(1)template用于声明一个模板
(2)typename/class来声明模板形参,模板形参是指传递给该函数的参数类型(模板形参就是该函数的参数类型),指定该函数里用的模板形参的类型
(3)模板形参要与函数形参一一对应
1.2 函数模板
关键字:template、class/typename
格式:
template <模板形参1,模板形参2,........>函数返回值 函数名 ([参数1,参数2,.......])
{
}
template <class T1,class T2,........>函数返回值 函数名 ([参数1,参数2,.......])
{
}
template <typename T1,typename T2,........>函数返回值 函数名 ([参数1,参数2,.......])
{
}
1.2.1 函数模板的调用
与C/C++普通函数调用一致:
隐式调用
格式:
函数名(实参1,实参2);//隐式调用(模板形参)
例如:
sum(10,20);
函数模板的显示调用(模板形参):
格式:
函数名 <数据类型1,数据类型2,.......>(实参1,实参2,......);
例如:
sum<int , char> (10,'a');
1.2.1.1 隐式调用
wide_practise.cpp
#include "iostream"
using namespace std;
//模板(泛型)
//声明函数模板写法1
template <class T1, class T2> void sum(T1 a,T2 b) {
T1 m = a;
T2 n = b;
cout << "m= " << m << endl;
cout << "n= " << n << endl;
}
声明函数模板写法2
//template <typename T1, typename T2> T1 sum(T1 a, T2 b) {
//
//}
//
声明函数模板写法3
//template <typename T1, typename T2> T2 sum(T1 a, T2 b) {
//
//}
int main()
{
sum(10, 20);
sum(10.2, 3.14);
sum(10,"hello world");
sum("hello","world");
sum("你好",10);
return 0;
}
1.2.1.2 显示调用
wide_practise.cpp
//模板(泛型)显示调用
//声明函数模板写法1
template <class T1, class T2> void sum(T1 a, T2 b) {
T1 m = a;
T2 n = b;
cout << "m= " << m << " n= " << n << endl;
}
int main()
{
sum(10,20);//隐式调用
sum<int, int>(50, 60);//显示调用
sum<int, char>(40, 'a');
return 0;
}
1.3.3 自定义类型调用
wide_practise.cpp
//模板(泛型)自定义类型
class People {
public:
int num = 90;
};
//声明模板函数
template <class T1, class T2> void sum(T1 a, T2 b) {
cout << "自定义类型的a= " << a.num << " b= " << b << endl;
}
int main()
{
People people;
sum(people, 80);//隐式调用
sum<People, int>(people, 55);//显示调用
return 0;
}
1.4 练习
编写如下形式的模板: template <class Type>void sort(Type* A, int n, bool f)
对一个具有n个Type类型的一维数组进行排序,f伪1表示从小到大排序, f为0表示从大到小排序
要求使用快速排序
wide_test.cpp
#include "iostream"
#include <stdbool.h>
using namespace std;
//编写如下形式的模板: template <class Type>void sort(Type* A, int n, bool f)
//对一个具有n个Type类型的一维数组进行排序,f伪1表示从小到大排序, f为0表示从大到小排序
//快速排序
//使用快速排序
//将快速排序也声明为模板函数
template<class Type> void quick_sort(Type arr[],int left,int right) {
//跳出递归的条件
if (left>=right) {
return;
}
//左右哨兵
int l = left;
int r = right;
//定义基准数
Type base = arr[left];
while (l!=r) {
//右哨兵先走,遇见比基准数小的就停下(即比基准数大就走动)
while(l<r && arr[r]>=base) {
r--;
}
//接着左哨兵走,遇见比基准数大的就停下(即比基准数小就走动)
while (l<r && arr[l]<=base) {
l++;
}
//当两个哨兵都停且没有相遇,就交换两个哨兵所指向的数据
if (l<r) {
Type tmp = arr[l];
arr[l] = arr[r];
arr[r] = tmp;
}
}
//两个哨兵相遇时,使哨兵所指的数据与基准数交换
//至此到这,交换后的基准数,左边都比自己小,右边都比自己大
if (l==r) {
Type tmp = arr[left];
arr[left] = arr[r];
arr[r] = tmp;
}
//进入递归
quick_sort<Type>(arr,left,r-1);
quick_sort<Type>(arr,r+1,right);
}
//声明模板
template<class Type> void sort(Type* arr, int n, bool f) {
if (f) {//f为真正序排序
//将快速排序也声明为模板函数
quick_sort<Type>(arr,0,n-1);
}
else {//为假倒叙排序
//我们现正排,然后反转数组,达到倒序排序的效果
quick_sort<Type>(arr, 0, n - 1);
int r = n;
//数组反转
for (int i = 0; i < n/2;i++) {
Type tmp = arr[i];
arr[i] = arr[r-1];
arr[r-1] = tmp;
r--;
}
}
}
int main()
{
//传递整型
int arr[] = { 8,4,1,2,7,13,2,4,8 };
int size = sizeof(arr)/sizeof(arr[0]);
sort<int>(arr, size, 0);
//遍历
for (int i = 0; i < size;i++) {
cout << arr[i]<<" ";
}
cout << endl;
//传递字符型
char arr2[] = { 'g','c','z','f','c','a'};
int size2 = sizeof(arr2) / sizeof(arr2[0]);
sort<char>(arr2, size2, 1);
//遍历
for (int i = 0; i < size2; i++) {
cout << arr2[i] << " ";
}
cout << endl;
//传递浮点型
double arr3[] = { 88.5,22.6,12.7,3.14,2.17,9.38 };
int size3 = sizeof(arr3) / sizeof(arr3[0]);
sort<double>(arr3, size3, 0);
//遍历
for (int i = 0; i < size3; i++) {
cout << arr3[i] << " ";
}
return 0;
}
2. 类模板
2.1 知识点
关键字:template、class/typename
格式:
template <模板形参1 , 模板形参2,非类型形参,......> class 类名
{
};
template <class T1 , class T2,int sum,......> class 类名
{
};
template <typename T1 , typename T2,int sum,......> class 类名
{
};
2.1.1 注:
(1)class T1/T2等是模板形参,int sum:非类型形参
非类型:是指实例化类的时候,不能传递类型,只能传递实参,非类型形参是整型:int\short\long等等,不能是字符串或浮点型等
(2)<>里的class用于声明模板形参 , 类名前的class用于声明一个类
2.2 举例
lei_template.cpp
#include "iostream"
using namespace std;
//声明模板类
//sum 这里的sum是非类型实参,传递时不能传递类型,要传递具体的值
template<class T1, class T2,int sum> class Animal {
public:
Animal(T1 a,T2 b) {
this->a = a;
this->b = b;
}
void diplay() {
cout << "a= " << a << " b= " << b << endl;
}
T1 a;
T2 b;
int arr[sum];//我们利用非类型实参,给这个数组属性定义大小
};
int main()
{
//实例化类模板
Animal<int, char,30> animal(10, 'v');
animal.diplay();
return 0;
}
2.3 练习
2.3.1 例1
我在一个类中定义了一个结构体,我又在类中写了一个成员函数,返回值是结构体类型,我在主函数中使用此成员函数,该怎么接收返回值呢
test.cpp
#include <iostream>
using namespace std;
class MyClass {
public:
// 定义一个结构体类型
struct MyStruct {
int data;
};
// 返回结构体类型的成员函数
MyStruct getStruct() {
MyStruct result;//定义结构类型
result.data = 42;//给结构体属性赋值
return result;//返回结构体类型
}
};
int main() {
// 实例化类对象
MyClass myObject;
// 调用成员函数并接收返回值
// MyClass::MyStruct 访问嵌套的结构体类型
// MyClass::MyStruct 这种语法对于访问嵌套类型、静态成员或命名空间中的元素是很常见的。
MyClass::MyStruct receivedStruct = myObject.getStruct();
// 输出结构体成员的值
cout << "Data in MyStruct: " << receivedStruct.data << endl;
return 0;
}
2.2.2 例2
我的写法
定义一个堆栈类模板,实现不同数据类型数据的入栈和出栈操作,堆栈的大小用非类型参数指定。
lei_template_test.cpp
#include "iostream"
#include<stdbool.h>
using namespace std;
typedef bool status;
#define MAXSIZE 10
//定义一个堆栈类模板,实现不同数据类型数据的入栈和出栈操作,堆栈的大小用非类型参数指定。
//定义模板类
template<class T> class Stack_ {
public:
struct Stack {
T stack[MAXSIZE];
int top;
};
//创建顺序栈
struct Stack* Stack_Create() {
struct Stack* p = (struct Stack*)malloc(sizeof(struct Stack));
if (p == NULL) {
return NULL;
}
//赋初值
memset(p->stack, 0, sizeof(p->stack));
p->top = -1;
return p;
}
//入栈
status Stack_Push(struct Stack* p, T data) {
//判断栈是否满了
if (p->top == MAXSIZE - 1) {
printf("栈已满,入栈失败\n");
return false;
}
p->top += 1;
p->stack[p->top] = data;
return true;
}
//出栈
status Stack_Pop(struct Stack* p, T* data) {
//判断栈是否为空
if (p->top == -1) {
printf("栈为空栈,出栈失败!\n");
return false;
}
*data = p->stack[p->top];
p->stack[p->top] = 0;//清空
p->top--;
return true;
}
//遍历栈
status Stack_Travel(struct Stack* p) {
//判断栈是否为空
int top_1 = p->top;
if (top_1 == -1) {
printf("栈为空栈,遍历失败\n");
return false;
}
while (top_1 >= 0) {
cout << p->stack[top_1] << " ";
top_1--;
}
return true;
}
// 释放堆栈
void Stack_Destroy(struct Stack* p) {
delete p; // 使用 delete 进行动态内存释放
}
};
int main()
{
//栈中存入int类型
//实例化类模板
Stack_<int> stack_;
Stack_<int>::Stack* p = stack_.Stack_Create();//Stack_<int>::Stack是在 C++ 中使用模板类 Stack 时访问内部嵌套结构 StackStruct 的方法。
//入栈
stack_.Stack_Push(p, 10);
stack_.Stack_Push(p, 20);
stack_.Stack_Push(p, 30);
stack_.Stack_Push(p, 40);
stack_.Stack_Push(p, 50);
//遍历
stack_.Stack_Travel(p);
cout << endl;
//出栈
int data;
stack_.Stack_Pop(p, &data);
cout << "取出栈顶元素为:" << data << endl;
//遍历
stack_.Stack_Travel(p);
//释放堆栈
stack_.Stack_Destroy(p);
cout << endl;
cout << endl;
//栈中存入char类型
//实例化类模板
Stack_<char> stack_2;
Stack_<char>::Stack* p2 = stack_2.Stack_Create();//Stack_<int>::Stack是在 C++ 中使用模板类 Stack 时访问内部嵌套结构 StackStruct 的方法。
//入栈
stack_2.Stack_Push(p2, 'a');
stack_2.Stack_Push(p2, 'b');
stack_2.Stack_Push(p2, 'c');
stack_2.Stack_Push(p2, 'd');
stack_2.Stack_Push(p2, 'e');
//遍历
stack_2.Stack_Travel(p2);
cout << endl;
//出栈
char data2;
stack_2.Stack_Pop(p2, &data2);
cout << "取出栈顶元素为:" << data2 << endl;
//遍历
stack_2.Stack_Travel(p2);
//释放堆栈
stack_2.Stack_Destroy(p2);
cout << endl;
cout << endl;
//栈中存入double类型
//实例化类模板
Stack_<double> stack_3;
Stack_<double>::Stack* p3 = stack_3.Stack_Create();//Stack_<int>::Stack是在 C++ 中使用模板类 Stack 时访问内部嵌套结构 StackStruct 的方法。
//入栈
stack_3.Stack_Push(p3, 3.14);
stack_3.Stack_Push(p3, 8.25);
stack_3.Stack_Push(p3, 1.22);
stack_3.Stack_Push(p3, 7.45);
stack_3.Stack_Push(p3, 6.489523);
//遍历
stack_3.Stack_Travel(p3);
cout << endl;
//出栈
double data3;
stack_3.Stack_Pop(p3, &data3);
cout << "取出栈顶元素为:" << data3 << endl;
//遍历
stack_3.Stack_Travel(p3);
//释放堆栈
stack_3.Stack_Destroy(p3);
return 0;
}
另一种写法
lei_template_test2.cpp
#include "iostream"
using namespace std;
//定义一个堆栈类模板,实现不同数据类型数据的入栈和出栈操作,堆栈的大小用非类型参数指定。
//
template<class T, int MAXSIZE>class Stack
{
public:
Stack()
{
stack = new T[MAXSIZE]{ 0 };//申请空间
this->top = -1;
}
//判断栈是否为空
bool isEmpty()
{
if (this->top == -1)
{
return true;
}
return false;
}
//判断栈是否为满
bool isFull()
{
if (this->top == MAXSIZE - 1)
{
cout << "栈已满!" << endl;
return true;
}
return false;
}
//入栈
bool Push(T data)
{
if (this->isFull())
{
return false;
}
this->top += 1;
this->stack[this->top] = data;
return true;
}
//出栈
bool Pop(T& data)
{
if (this->isEmpty())
{
return false;
}
data = this->stack[this->top];
this->stack[this->top] = 0;
this->top--;
return true;
}
//返回栈顶元素
bool get_Top_Data(T& data)
{
if (this->isEmpty())
{
return false;
}
data = this->stack[this->top];
}
//打印栈中的数据
void display()
{
for (int i = 0; i < MAXSIZE; i++)
{
cout <<this->stack[i] <<" ";
}
}
~Stack()
{
delete[]stack;//释放资源
}
private:
int top;//指向栈顶指针
T* stack;
};
int main()
{
//实例化一个类 int类型的栈
Stack<int, 10>stack;
//看看栈是否已满
bool flag = stack.isFull();
if (flag) {
}
else {//不满添加数据
stack.Push(10);
stack.Push(20);
stack.Push(30);
stack.display();
}
//看看栈是否为空
flag = stack.isEmpty();
if (flag)
{
cout << "栈为空!" << endl;
}
else
{
cout << endl;
int data;
stack.Pop(data);
cout << "取出栈顶元素为:" << data << endl;
stack.display();
}
cout << endl;
//实例化一个类,char类型的栈
Stack<char, 10>stack2;
//看看栈是否已满
bool flag2 = stack2.isFull();
if (flag2) {
}
else {//不满添加数据
stack2.Push('a');
stack2.Push('b');
stack2.Push('c');
stack2.display();
}
//看看栈是否为空
flag2 = stack2.isEmpty();
if (flag2)
{
cout << "栈为空!" << endl;
}
else
{
cout << endl;
char data2;
stack2.Pop(data2);
cout << "取出栈顶元素为:" << data2 << endl;
stack2.display();
}
return 0;
}
2.2.3 使用通用模板类写一个冒泡排序
bubble_sort.cpp
#include "iostream"
using namespace std;
//使用通用模板类写一个冒泡排序
class People {
public:
People(char c) {
str = c;
}
// 重载 > 运算符
bool operator>(const People& other) const {
return this->str > other.str;
}
char str;
};
template<class T> class b_sort {
public:
void bubble_sort(T arr[], int sz) {
for (int i = 0; i < sz - 1; i++) {
for (int j = 0; j < sz - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
T tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
}
};
int main()
{
//实例化一个对象
//排序整型
b_sort<int> sort;
int arr[] = { 8,3,1,5,63,2,7,9};
int sz = sizeof(arr) / sizeof(arr[0]);
sort.bubble_sort(arr,sz);
for (int i = 0; i < sz;i++) {
cout << arr[i] << " ";
}
cout << endl;
cout << endl;
//实例化一个对象
//排序字符型
b_sort<char> sort2;
char arr2[] = {'f','r','w','h','b','a'};
int sz2 = sizeof(arr2) / sizeof(arr2[0]);
sort2.bubble_sort(arr2, sz2);
for (int i = 0; i < sz2; i++) {
cout << arr2[i] << " ";
}
cout << endl;
cout << endl;
//实例化一个对象
//排序自定义类型
b_sort<People> sort3;
People people1('l');
People people2('z');
People people3('l');
People people4('i');
People arr3[] = {people1,people2,people3,people4 };
int sz3 = sizeof(arr3) / sizeof(arr3[0]);
sort3.bubble_sort(arr3, sz3);
for (int i = 0; i < sz3; i++) {
cout << arr3[i].str << " ";
}
return 0;
}