C++提高编程-模板

模板的基本概念

模板的主要用于提高C++的泛型编程而设计的,可以把模板理解为通用的模具,大大提高复用性,这和字面意思也差不多。

函数模板

函数模板基本概念

image

template<typename T>  //typename可以替换成class
写函数,其中变量用T表示

实例代码如下:

//函数模板语法如下
//声明的意义在于告诉编译器,紧跟的函数中的T不要报错,为泛型
template<typename T>
void Swap(T& a, T& b)
{
	T temp = a;
	a = b;
	b = temp;
}

void test01()
{
	int a = 10;
	int b = 20;
	//模板使用方法如下
	//1.自动类型推导
	Swap(a, b);
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	//2.显示告知
	Swap<int>(a, b);
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
}

使用函数模板时,必须确定出通用数据类型T,并且能够推导出一致的类型。

普通函数和函数模板的区别

image
示例代码如下:

//普通函数
int add(int a, int b)
{
	return a + b;
}

//函数模板
template<typename T>
int myAdd(T a, T b)
{
	return a + b;
}

void test01()
{
	int a = 10;
	int b = 20;
	char c = 'a';
	//普通函数可以隐式类型转换
	cout << add(a, c) << endl;

	//模板函数自动类型推导,无法进行隐式类型转换
	//cout << myAdd(a, c) << endl;

	//模板函数显示指定类型,可以进行隐式类型转换
	cout << myAdd<int>(a, c) << endl;
}

普通函数和函数模板的区别

image
实例代码如下:

//普通函数和函数模板调用规则
//1.如果函数模板和普通函数都可以调用,优先调用普通函数
//2.可以通过空模板参数列表 强制调用函数模板
//3.函数模板可以发生函数重载
//4.如果函数模板可以产生更好的匹配,优先调用函数模板

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

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

//函数模板可以发生重载
template<typename T>
void myPrint(T a)
{
	cout << "调用重载的函数模板" << endl;
}

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

	//都可以调用时,优先调用普通函数
	myPrint(a, b);

	//通过空模板参数列表,强制调用模板
	myPrint<>(a, b);
	myPrint<int>(a, b);

	//函数模板可以发生承载
	myPrint(a);

	//如果函数模板可以产生更好的匹配,优先调用函数模板
	char c1 = 'a';
	char c2 = 'b';
	myPrint(c1, c2);

}

模板局限性

示例代码如下:

//模板局限性
//模板并不是万能的,有些特定数据类型,需要用具体化方式做特殊实现

class Person
{
public:
	Person(string name, int age)
	{
		this->m_Age = age;
		this->m_Name = name;
	}
	//1.第一种方法,可以采用重载运算符的方法实现.
	/*bool operator==(const Person& p)
	{
		if (this->m_Age == p.m_Age && this->m_Name == p.m_Name)
			return true;
		return false;
	}*/

	string m_Name;
	int m_Age;
};

//对比两个数据是否相等
template<typename T>
bool myCompare(T& a, T& b)
{
	if (a == b)
	{
		return true;
	}
	return false;
}

//2,第二种解决办法,对模板具体化,优先调用
template<> bool myCompare(Person& a, Person& b)
{
	if (a.m_Age == b.m_Age && a.m_Name == b.m_Name)
		return true;
	return false;
}


void test01()
{

	Person p1("Tom", 12);
	Person p2("Tom", 12);

	bool ret = myCompare(p1, p2);

	if (ret)
	{
		cout << "p1 == p2" << endl;
	}
	else
	{
		cout << "p1 != p2" << endl;
	}

}

类模板

类模板语法

image
示例代码如下:

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

	NameType m_Name;
	AgeType m_Age;
};

void test01()
{
	Person<string,int> p1("孙悟空", 999);
	
	p1.show_Person();
}

类模板和函数模板的区别

示例代码如下:

//类模板和函数模板的区别
//1.类模板没有自动类型推导
//2.类模板参数列表中可以有默认参数

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

	NameType m_Name;
	AgeType m_Age;
};

void test01()
{

	//Person p1("孙悟空", 999); //错误,类模板没有自动类型推导
	Person <string>p("猪八戒", 1888);
	p.show_Person();
	
}

类模板中成员函数创建时机

image
很好理解,创建时,并不知道类模板中参数类型,所以函数中并不知道参数,无法有效的调用。
当调用函数时,才知道参数列表,这时才会创建函数。

类模板对象作为函数参数

示例代码如下:

//类模板对象做函数参数

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

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

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

	T1 m_Age;
	T2 m_Name;
};

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

//2.参数模板化(感觉和函数模板没啥区别嘞)
template<typename T1,typename T2>
void printPerson2(Person<T1, T2>& p)
{
	p.showPerson();

	cout << "T1的推导参数类型为:" << typeid(T1).name() << endl;

	cout << "T1的推导参数类型为:" << typeid(T2).name() << endl;
}

//3.整个类模板化
template<typename T>
void printPerson3(T& p)
{
	p.showPerson();

	cout << "T的数据类型为:" << typeid(T).name() << endl;
}

void test01()
{
	Person<int, string>p1(11, "孙悟空");
	printPerson(p1);

	Person<int, string>p2(18, "猪八戒");
	printPerson2(p2);

	Person<int, string>p3(21, "沙和尚");
	printPerson3(p3);

}

类模板与继承

示例代码如下:

//类模板与继承
template<class T>
class Base
{
	T m;
};

//1.子类继承类模板时,必须指明父类的参数类型
class Son : public Base<int>
{
	int m;
};

//2.如果想要灵活指定父类中的T类型的话,子类也需要编程类模板
template<class T>
class Son1 : public Base<T>
{
	T m;
};

模板类外实现成员函数


//模板类,类外外实现成员函数
template<class T1, class T2>
class Person
{
public:

	Person(T1 name, T2 age);

	void show_Person();

	T1 m_Name;
	T2 m_Age;

};

//类外实现构造函数
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{
	this->m_Age = age;
	this->m_Name = name;
}

//类外实现普通成员函数
template<class T1,class T2>
void Person<T1, T2>::show_Person()
{
	cout << this->m_Name << ' ' << this->m_Age << endl;
}

void test01()
{
	Person<string, int> p("张三", 18);
	p.show_Person();
}

类模板的分文件编写

正常情况下,类模板的分文件编写应该如下:
Person.h文件代码如下:

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

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

	Person(T1 name, T2 age);

	void show_Person();

	T1 m_Name;
	T2 m_Age;

};

Person.cpp文件代码如下:

#pragma once
#include "person.h"

//类外实现构造函数
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{
	this->m_Age = age;
	this->m_Name = name;
}

//类外实现普通成员函数
template<class T1, class T2>
void Person<T1, T2>::show_Person()
{
	cout << this->m_Name << ' ' << this->m_Age << endl;
}

然后在要使用的文件中加上#include "Person.h"语句,即可正常调用,但发现出现问题,因为在之前提到过,类模板的成员函数创建时机是调用时才创建,所以在链接阶段,源文件中只包含了.h文件,虽然.h文件中有函数的声明,但成员函数由于未调用,所以并没有链接到这些成员函数,这样就无法调用。
解决办法一:直接在要使用的文件中加上#include"Person.cpp"语句。
解决办法二:将.h和.cpp文件合并,后缀名改为.hpp文件,包含.hpp文件即可。

类模板与友元

示例代码如下:

//将类的声明提前,方便接下来函数的实现
template<class T1, class T2>
class Person;

//需要将函数实现提前到函数前,由于声明中有Person,所以还需将Person类的声明你提起按
template<class T1, class T2>
void printPerson2(Person<T1, T2>& p)
{
	cout << "类外实现友元全局函数 " << p.m_Name << ' ' << p.m_Age << endl;
}


template<class T1, class T2>
class Person
{
	//友元全局函数,类内实现
	friend void printPerson(Person<T1, T2>& p)
	{
		cout << "类内实现友元全局函数 " << p.m_Name << ' ' << p.m_Age << endl;
	}

	//友元全局函数,类外实现
	//为了声明这是全局函数,这里需要加上<>,参数列表
	friend void printPerson2<>(Person<T1, T2>& p);
	
public:

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

	T1 m_Name;
	T2 m_Age;
};



void test01()
{
	Person<string, int> p("张三", 18);
	printPerson(p);

	printPerson2(p);
}

posted @ 2024-11-18 22:46  逆天峰  阅读(15)  评论(0)    收藏  举报
作者:逆天峰
出处:https://www.cnblogs.com/gcfer//