C++ | 期末冲刺版⑥

目录

模板

函数模板

案例 (从大到小排序)

类模板

类模板语法类模板作用:

类模板与函数模板的区别

类模板与继承

类模板成员函数类外实现

案例(拷贝构造 | 深浅拷贝问题)

等号重载

重载 ' [ ] '

为什么返回引用?


模板

函数模板

语法:

template<typename T>
函数声明或定义
//函数模板
//声明一个模板,告诉编译器后面的代码中紧跟着的T不要报错,T是一个通用数据类型
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);

	

	double c = 11.1;
	double d = 12.2;
	//显示指定类型
	MySwap<double>(c, d);
	
}

 MySwap<double>(c,d);

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

案例 (从大到小排序)

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++)
		{
			//认定的最大值比遍历出的数值要小,说明j下标的元素才是真正的最大值
			if (arr[max] < arr[j])
			{
				max = j;
			}
		}
		if (max != i)
		{
			//交换max和i元素
			mySwap(arr[max], arr[i]);
		}
	}
}

int a = 10;
	int b = 20;
	char c = 'c';
	cout << myAdd01(a, c) << endl;

	//自动类型推导不行
	//cout << myAdd02(a, c) << endl;

	//显式指定类型行
	cout << myAdd02<int>(a, c) << endl;


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;
	}
}

 为什么第二个<>中为空

在函数模板具体化的语法中,可以省略模板参数类型,编译器会自动根据函数参数类型来推导模板参数类型。


类模板

类模板语法
类模板作用:

建立一个通用类, 类中成员数据可以不具体指定,用一个虚拟的类型来代表
语法:

template<typename T>
 

template< typename T>——声明创建模板

typename——表明其后面的符号是一种数据类型,可以用class代替 

T——通用的数据类型,名称可以替换,通常为大写字母


类模板与函数模板的区别

类模板与函数模板的区别主要有两点:

  1. 类模板没有自动类型推导的使用方式
  2. 类模板在模板参数列表中可以有默认参数

    类模板与继承

    当类模板碰到继承时,需要注意一下几点:

  3. 当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中T的类型
  4. 如果不想指定,编译器无法给子类分配内存‘
  5. 如果想灵活指定出父类中T的类型,子类也需要变为类模板
  6. //类模板与继承
    template<class T>
    class Base
    {
    	T m;
    };
    class Son :public Base<int>//必须要知道父类中T的数据类型才能继承给子类
    {
    
    };
    
    
    //如果想灵活指定父类中T类型,子类也需要变类模板
    template<class T1,class T2>
    class Son2 :public Base<T2>
    {
    public:
    	Son2()
    	{
    		cout << typeid(T1).name()<< endl;
    		cout << typeid(T2).name()<< endl;
    	}
    	T1 obj;
    };
    
    
    

    类模板成员函数类外实现

    template<class T1,class T2>
    class Person
    {
    public:
    void showPerson();
    T1 m_Name;
    T2 m_Age;
    };
    //构造函数类外实现
    
    template<class T1,class T2>
    void Person<T1,T2>::showPerson()
    {
    
    }
    
    

template<模板参数表>

类型名 类名<模板参数标识符列表>::函数名(参数表)

// void Person<T1,T2>::showPerson()
 


案例(拷贝构造 | 深浅拷贝问题)

//拷贝构造
	MyArry(const MyArry& arr)
	{
		//cout << "MyArry的拷贝构造调用" << endl;

		this->m_Capacity = arr.m_Capacity;
		this->m_Size = arr.m_Size;
		//this->pAddress = arr.pAddress;

		//深拷贝
		this->pAddress = new T[arr.m_Capacity];//不是T[arr.pAddress,而是按照你传进来的数组的容量;
		
		//将arr中的数据都拷贝过来
		for (int i = 0; i < this->m_Size; i++)
		{
			this->pAddress[i] = arr.pAddress[i];
		}
	}

等号重载

//operator= 防止浅拷贝问题
	MyArry& operator =(const MyArry& arr)
	{

		//cout << "MyArry的operator=调用" << endl;

		//先判断原来堆区是否有数据,如果有先释放
		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];
		}
		return *this;
	}

如果你想返回void,原式:a=b=c;//想做连等的操作,发现不行;

只能返回引用;


重载 ' [ ] '

T& operator[](int index)

{ return this->pAddress[index]; }


为什么返回引用?

这个代码返回引用是因为它想要实现对数组元素的修改。当我们使用 `[]` 运算符访问数组元素时,通常会返回一个值,这个值是数组元素的副本。但是,如果我们想要修改数组元素,我们需要返回一个引用,这样我们才能通过引用修改原始数组元素的值。 在这个代码中,`this->pAddress[index]` 返回的是一个 `T` 类型的值,但是通过 `return` 关键字返回时,它被转换为了一个 `T&` 类型的引用。这样,当我们使用 `[]` 运算符访问数组元素并且对其进行修改时,实际上是修改了原始数组元素的值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值