C++核心编程和桌面应用开发 第十天(模版 类模板)

发布于:2024-10-15 ⋅ 阅读:(65) ⋅ 点赞:(0)

目录

1.1函数模板语法

1.2函数模板的使用方式

1.2.1自动类型推导

1.2.2显示指定类型

1.3普通函数与模板函数

1.3.1区别

1.3.2调用规则

1.4模板的局限性

1.4.1模板的具体化

1.5类模板

1.5.1基本语法

1.5.2类模板对象做函数参数

1.5.3类模板与继承

1.5.4类模板成员函数类外实现

1.5.5类模板分文件编写

1.5.6类模板与友元

1.5.6.1类内实现

1.5.6.2类外实现

 1.5.7举例:通过类模板创建数组类MyArray


1.1函数模板语法

建立通用的模具,大大提高复用性,模板只是一个框架,不可以直接使用

//T代表数据类型
template<typename T>

void mySwap(T& a, T& b)
{
	T temp = a;
	a = b;
	b = temp;
}

1.2函数模板的使用方式

1.2.1自动类型推导

int a = 10;
int b = 20;

mySwap(a, b);

编译器会自动推导出T的类型为int

1.2.2显示指定类型

int a = 10;
int b = 20;

mySwap<int>(a, b);

明确指定T的类型为int 

注意事项:

①自动类型推导,必须正确推出T的类型,否则无法成功调用函数

 ②模版必须指定或推导出T的类型,否则不可单独使用

1.3普通函数与模板函数

1.3.1区别

  • 普通函数调用时,可以发生自动类型转换(隐式类型转换);
  • 函数模板调用时,若利用自动类型推导,不会发生隐式类型转换;若利用显示指定类型,可以发生隐式类型转换。

1.3.2调用规则

  • 函数模板和普通函数都可以实现时,优先使用普通函数
  • 可以通过空模板参数列表强制调用函数模板
  • 函数模板可以重载
  • 若函数模板可以产生更好的匹配,优先调用函数模板

注意:通过函数模板产生的函数,称为模板函数

myPrint(c1,c2)会调用函数模板,因为若调用普通函数,会进行类型转换,而调用函数模板,直接就能获取到数据类型,代价更小,因此调用函数模板

1.4模板的局限性

解决办法:

  • 运算符重载。重载运算符>
  • 为特定的类型(Person)提供具体化的模板

1.4.1模板的具体化

普通模板:

template<class T>
bool myCompare(T& a, T& b)
{
	if (....)
	...
}

具体化语法:以template<>开头,通过名称指出类型(提供对比功能的函数模板)

template<>bool myCompare(Person& a, Person& b)
{
	if (....)
	...
}

注意:若参数类型符合模板具体化的参数类型时,模板的具体化调用优先于普通模板的调用

1.5类模板

1.5.1基本语法

//typename也可以用class替换
template<typename T>
class ...
{
    ...
};

建立一个通用类,类中成员的数据类型不固定

注意事项:

1.模板参数列表可以有默认参数;

2.类模板没有自动推导;

3.类模板中的成员函数在被调用的时候才被创建

1.5.2类模板对象做函数参数

类模板如下:

 1. 指定传入类型。即形参的模板参数列表明确数据类型

void doWork1(Person<string,int>& p);

2.参数模板化。即形参的模板参数列表也变为通用类型

注意:typeid(T).name() 查看T的数据类型

3.整个类模板化。即形参中对象的类型变为模板

1.5.3类模板与继承

①父类为类模板时,子类在继承时必须指定父类中T的类型,否在无法给子类分配内存

②父子类均为类模板时,在子类继承时,将模板参数列表改为T

1.5.4类模板成员函数类外实现

语法:

template<class T>
返回值类型 类名<T>::成员函数名(形参列表)

1.5.5类模板分文件编写

分文件编写会产生错误,因为类模板成员函数是在被调用时才创建的,分文件编写后,只能访问头文件,访问不到源文件的内容

解决办法:

  • 将源文件包含进来。此做法不安全
  • 将源文件和头文件结合到一个文件中,即hpp中

1.5.6类模板与友元

1.5.6.1类内实现

1.5.6.2类外实现

在类中声明友元时,需将printPerson作为函数模板声明,语法如下:

friend void printPerson<>(Person<T1,T2>& p);

注意:

  • 若函数实现写在类之前,需要提前声明类之后使用
  • 若函数实现写在类之后,需要提前声明函数和类之后使用

 1.5.7举例:通过类模板创建数组类MyArray

template<class T>
class MyArray
{
public:
	//有参构造
	MyArray(int capacity)
	{
		m_Capacity = capacity;
		m_Size = 0;
		pAddress = new T[m_Capacity];
	}

	//拷贝构造
	MyArray(const MyArray& arr)
	{
		m_Capacity = arr.m_Capacity;
		m_Size = arr.m_Size;
		if (nullptr != arr.pAddress)
		{
			pAddress = new T[m_Capacity];
			strcpy(arr.pAddress, pAddress, m_Size);
		}
	}

	//析构函数
	~MyArray()
	{
		if (nullptr != pAddress)
		{
			delete[] pAddress;
			pAddress = nullptr;
		}
	}

	//operator=
	MyArray& operator=(const MyArray& arr)
	{
		if (nullptr != pAddress)
		{
			delete[] pAddress;
			pAddress = nullptr;
		}
		m_Capacity = arr.m_Capacity;
		m_Size = arr.m_Size;
		pAddress = new T[m_Capacity];
		strcpy(arr.pAddress, pAddress, m_Size);

		return *this;
	}

	//operator[]
	T& operator[](int pos)
	{
		return pAddress->[pos];
	}

	//尾插
	void pushBack(T val)
	{
		if (m_Capacity == m_Size)
		{
			return;
		}
		pAddress[m_Size] = val;
		m_Size++;
	}

	//删掉末尾元素
	void popBack()
	{
		if (m_Size == 0 || m_Capacity == 0)
		{
			return;
		}
		m_Size--;
	}

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

	//获取当前大小
	int getSize()
	{
		return m_Size;
	}
private:
	int m_Capacity;

	int m_Size;

	T* pAddress;
};


网站公告

今日签到

点亮在社区的每一天
去签到