IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> Day34.C++08 -> 正文阅读

[C++知识库]Day34.C++08

Day34.C++08

001.函数模板的基本使用

模板概论:

C++提供了函数模板,所谓函数模板,实际上就是建立一个通用函数,其函数类型和形参类型不具体制定,用一个虚拟的类型来代表。这个通用函数就成为函数模板。
凡是函数体相同的函数都可以用这个模板代替,不必定义多个函数,只需在模板中定义一次即可。在调用函数时系统会根据实参的类型来取代模板中的虚拟类型,从而实现不同函数的功能。

代码示例:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

//交换两个int类型的数据
void mySwapInt(int& a, int& b)
{
	int tmp = a;
	a = b;
	b = tmp;
}

//交换两个double类型的数据
void mySwapDouble(double& a, double& b)
{
	double tmp = a;
	a = b;
	b = tmp;
}

//类型,逻辑非常相似
//类型参数化 泛型编程——模板技术
template<class T>//告诉编译器 下面如果出现了T不要报错,T是一个通用的类型
void mySwap(T& a, T& b)
{
	T tmp = a;
	a = b;
	b = tmp;
}

template<typename T>//等价于     template<class T>
void mySwap2()
{

}

void test01()
{
	int a = 10;
	int b = 20;
	//mySwapInt(a, b);
	//1. 自动类型推导,必须有参数类型才可以推导
	mySwap(a, b);

	//2. 显示指定类型
	mySwap<int>(a, b);

	//模板那必须要指定出T才可以使用
	mySwap2<double>();

	cout << "a = " << a << "   b = " << b << endl;

	double c = 3.14;
	double d = 1.5;
	//mySwapDouble(c, d);
	mySwap(c, d);
	cout << "c = " << c << "   d = " << d << endl;

}

int main(void)
{
	test01();

	system("pause");
	return EXIT_SUCCESS;
}

002.练习-利用模板对int类型和char类型的数组进行排序

代码:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

//对char和int类型数组进行排序,排序规则 从大到小 利用选择排序
template<class T>
void mySwap(T& a, T& b)
{
	T tmp = a;
	a = b;
	b = tmp;
}

template<class 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<class T>
void myPrintArray(T arr[],int len)
{
	for (int i = 0; i < len; ++i)
	{
		cout << arr[i] << " ";
	}
	cout << endl;
}

void test01()
{
	int intArr[] = { 5,96,8,9,7,5,1,2,3,5654,4154,125315,2246 };
	int len1 = sizeof(intArr) / sizeof(intArr[0]);
	mySort<int>(intArr, len1);
	myPrintArray<int>(intArr, len1);

	char charArray[] = "helloworld";
	int len2 = sizeof(charArray) / sizeof(char);
	mySort(charArray, len2);
	myPrintArray(charArray, len2);
}

int main(void)
{
	test01();

	system("pause");
	return EXIT_SUCCESS;
}

003.函数模板与普通函数的区别以及调用规则

结论:

- 普通函数与函数模板的区别
	函数模板不可以进行隐式类型转换
	普通函数可以进行隐式类型转换
- 普通函数和函数模板的调用规则
	1. 如果出现重载,优先使用普通函数调用(如果没有实现,出现错误)
	2. 如果想强制调用模板,那么可以使用空参数列表
	3. 函数模板可以发生重载
	4. 如果函数模板可以产生更好的匹配,那么优先调用函数模板

代码示例:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

//1. 普通函数与函数模板的区别
template<class T>
T myPlus1(T a, T b)
{
	return a + b;
}

int myPlus2(int a, int b)
{
	return a + b;
}

void test01()
{
	int a = 10;
	int b = 20;
	char c = 'c';//'a' = 97

	//myPlus1(a, c);//类型推导不出来,函数模板不可以进行隐式类型转换
	cout << myPlus2(a, c) << endl;//普通函数可以进行隐式类型转换
}

//2. 普通函数和函数模板的调用规则
template<class T>
void myPrint(T a, T b)
{
	cout << "模板函数调用的myPrint" << endl;
}

void myPrint(int a, int b)
{
	cout << "普通函数调用的myPrint" << endl;
}

template<class T>
void myPrint(T a, T b,T c)
{
	cout << "模板函数调用的myPrint(a,b,c)" << endl;
}

void test02()
{
	int a = 10;
	int b = 20;

	//1. 如果出现重载,优先使用普通函数调用(如果没有实现,出现错误)
	myPrint(a, b);

	//2. 如果想强制调用模板,那么可以使用空参数列表
	myPrint<>(a, b);

	//3. 函数模板可以发生重载
	int c = 30;
	myPrint(a, b, c);

	//4. 如果函数模板可以产生更好的匹配,那么优先调用函数模板
	char d = 'd';
	char e = 'e';
	myPrint(d, e);

	
}

int main(void)
{
	//test01();
	test02();

	system("pause");
	return EXIT_SUCCESS;
}

004.函数模板的局限性以及解决

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;

class Person
{
public:
	Person(string name,int age)
	{
		this->m_Age = age;
		this->m_Name = name;
	}

	string m_Name;
	int m_Age;
};

template<class T>
bool myCompare(T& a, T& b)
{
	if (a == b)
	{
		return true;
	}
	return false;
}

//通过具体化自定义数据类型,解决上述问题
//如果具体化能够优先匹配,那么就选择具体化
//语法:template<>返回值 函数名(具体类型参数)
template<>bool myCompare(Person& a, Person& b)
{
	if (a.m_Age == b.m_Age)
	{
		return true;
	}
	return false;
}

void test01()
{
	int a = 10;
	int b = 20;
	
	int ret1 = myCompare(a, b);
	cout << "ret1 = " << ret1 << endl;

	Person p1 = { "Tom",10 };
	Person p2 = { "Jerry",20 };

	int ret2 = myCompare(p1, p2);
	cout << "ret2 = " << ret2 << endl;
}

int main(void)
{
	test01();

	system("pause");
	return EXIT_SUCCESS;
}

005.类模板的基本使用

总结:

写法:template<class T1,class T2···>
与函数模板的区别,可以有默认类型参数
函数模板可以进行自动类型推导,而类模板不可以
成员函数 一开始不会创建出来,而是在运行的时候被创建出来

代码示例:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

//类模板
template<class NameType,class AgeType>
class Person
{
public:
	Person(NameType name, AgeType age)
	{
		this->m_Name = name;
		this->m_Age = age;
	}

	void showPerson()
	{
		cout << this->m_Name << "的年龄是" << this->m_Age << endl;
	}

	NameType m_Name;
	AgeType m_Age;

};

void test01()
{
	//自动类型推导,类模板,不支持
	//Person p("孙悟空", 100);

	//显示指定类型
	Person<string, int>p("孙悟空", 500);

	p.showPerson();
}

int main(void)
{
	test01();

	system("pause");
	return EXIT_SUCCESS;
}

006.类模板做函数的参数

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;

//类模板
template<class NameType, class AgeType>
class Person
{
public:
	Person(NameType name, AgeType age)
	{
		this->m_Name = name;
		this->m_Age = age;
	}
	void showPerson()
	{
		cout << this->m_Name << "的年龄是" << this->m_Age << endl;
	}
	NameType m_Name;
	AgeType m_Age;
};

//1.指定传入类型
void doWork(Person<string, int>& p)
{
	p.showPerson();
}

void test01()
{
	Person<string, int>p("MT", 10);
	doWork(p);
}

//2.参数模板化
template<class T1, class T2>
void doWork2(Person<T1,T2>& p)
{
	//如何查看类型
	cout << "T1 的类型:" << typeid(T1).name() << endl;
	cout << "T2 的类型:" << typeid(T2).name() << endl;
	
	p.showPerson();
}

void test02()
{
	Person<string, int>p("狗贼", 10);
	doWork2(p);
}

//3.整体模板化
template<class T>
void doWork3(T& p)
{
	p.showPerson();
}

void test03()
{
	Person<string, int>p("戴比", 20);

	doWork3(p);
}

int main(void)
{
	test01();
	test02();
	test03();

	system("pause");
	return EXIT_SUCCESS;
}

007.类模板碰到继承问题

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

template<class T>
class Base
{
public:
	
	T m_A;
};

//child 继承于 base ,必须告诉base中的T的类型,否则T无法分配内存
class Child :public Base<int>
{

};

//child2 也是模板类
template<class T1,class T2>
class Child2 :public Base<T2>
{
public:
	Child2()
	{
		cout << "T1的类型: " << typeid(T1).name() << endl;
		cout << "T2的类型: " << typeid(T2).name() << endl;
	}

public:

	T1 m_B;
};

void test01()
{
	Child2<int,double>child;//由用户指定类型
}

int main(void)
{
	test01();

	system("pause");
	return EXIT_SUCCESS;
}

008.类模板的类外实现成员函数

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

template<class T1,class T2>
class Person
{
public:

	Person(T1 name, T2 age);
	
	void showPerson()
	{
		cout << "姓名:" << this->m_Name << "  " << "年龄:" << this->m_Age << endl;
	}

	T1 m_Name;
	T2 m_Age;
};

template<class T1,class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{
	
	this->m_Name = name;
	this->m_Age = age;
}

void test01()
{
	Person<string, int>p("孙悟空", 100);
	p.showPerson();
}

int main(void)
{
	test01();

	system("pause");
	return EXIT_SUCCESS;
}

009.类模板的分文件编写问题以及解决

- .h 和 .cpp 分别写声明和实现
- 但是由于 类模板的成员函数运行阶段才去创建,导致包含.h头文件,不会创建函数的实现,无法解析外部命令
- 建议 模板不要做分文件编写,写到一个类中即可,类内进行声明和实现,最后把后缀名改为 .hpp

010.类模板碰到友元函数-类内实现

friend void printPerson(Person<string,int>& p)

011.类模板碰到友元函数-类外实现

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;

//让编译器提前看到printPerson的声明
//让编译器看到Person类的声明
template<class T1, class T2>class Person;
template<class T1, class T2>void printPerson(Person<T1, T2>& p);

template<class T1, class T2>
class Person
{
	//利用空参数列表,告诉编译器 这是模板函数的声明
	friend void printPerson<>(Person<T1, T2>& p);
	/*{
		cout << "姓名:" << p.m_Name << "  年龄:" << p.m_Age << endl;
	}*/
public:
	Person(T1 name, T2 age)
	{
		this->m_Name = name;
		this->m_Age = age;
	}

private:
	T1 m_Name;
	T2 m_Age;
};

template<class T1, class T2>
void printPerson(Person<T1, T2>& p)
{
	cout << "姓名:" << p.m_Name << "  年龄:" << p.m_Age << endl;
}



void test01()
{
	Person<string, int>p("者行孙", 1500);
	printPerson(p);
}

int main(void)
{
	test01();

	system("pause");
	return EXIT_SUCCESS;
}

012.类模板的应用-数组类封装

MyArray.hpp

#pragma once
#include<iostream>
using namespace std;


template<class T>
class MyArray
{
public:
	//构造函数
	explicit MyArray(int capacity)  //防止隐式类型转换 防止MyArray arr = 10; 的写法
	{
		this->m_Capacity = capacity;
		this->m_Size = 0;
		this->pAddress = new T[m_Capacity];
	}

	MyArray(const MyArray& array)
	{
		this->m_Capacity = array.m_Capacity;
		this->m_Size = array.m_Size;
		this->pAddress = new T[array->m_Capacity];
		for (int i = 0; i < this->m_Size; ++i)
		{
			this->pAddress[i] = array.pAddress[i];
		}
	}

	~MyArray()
	{
		if (this->pAddress != NULL)
		{
			delete[] this->pAddress;
			this->pAddress = NULL;
		}
	}

	//赋值操作符重载
	MyArray& operator=(const MyArray& array)
	{
		//先判断原始数据,有的话就清空
		if (this->pAddress != NULL)
		{
			delete[] this->pAddress;
			this->pAddress = NULL;
		}
		this->m_Capacity = array.m_Capacity;
		this->m_Size = array.m_Size;
		this->pAddress = new T[array->m_Capacity];
		for (int i = 0; i < this->m_Size; ++i)
		{
			this->pAddress[i] = array.pAddress[i];
		}
	}

	//[]重载
	T& operator[](int index)
	{
		return this->pAddress[index];
	}

	//尾插法
	void push_Back(T val)
	{
		this->pAddress[this->m_Size] = val;
		this->m_Size++;
	}

	//获取大小
	int getSize()
	{
		return this->m_Size;
	}

	//获取容量
	int getCapacity()
	{
		return this->m_Capacity;
	}



private:
	T* pAddress;//指向堆区空间
	int m_Capacity;
	int m_Size;



};

类模板的应用-数组类的封装.cpp

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include"MyArray.hpp"

//输出int类型的数组
void printIntArray(MyArray<int>& array)
{
	for (int i = 0; i < array.getSize(); ++i)
	{
		cout << array[i] << endl;
	}
}

int main(void)
{
	MyArray<int> arr(10);
	for (int i = 0; i < 10; ++i)
	{
		arr.push_Back(i * i);
	}
	printIntArray(arr);

	system("pause");
	return EXIT_SUCCESS;
}
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-23 10:32:07  更:2021-07-23 10:33:59 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 10:13:41-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码