【C++模板编程入门】模板介绍、模板定义、函数模板、类模板、模板的继承

1、模块的引入

1.1、示例代码

#include <iostream>
#include <string>

using namespace std;

//用template声明T是模板类
template <typename T>
T add(T a, T b)
{
	return a + b;
}

int main(void)
{
	//给add函数传入int类型,此时T就会被替换成int类型:int add(int a, int b)
	int var1 = add(11, 22);
	
	//给add函数传入double 类型,此时T就会被替换成double类型:double add(double a, double b)
	double var2 = add(11.11, 22.22);

	cout << "var1=" << var1 << ", var2=" << var2 << endl;

	return 0;
}

1.2、代码分析

root@ubuntu:# ./app 
var1=33, var2=33.33

(1)用template声明T是模板类型,也就是表示T是泛指数据类型,不是具体的数据类型;
(2)add的参数用T来表示,说明add函数的传参和返回值都是模板类型,需要在调用add函数时来指定;
(3)用模板来定义add函数使得代码更简洁,如果不使用模板则需要定义多个不同传参类型的add函数来实现函数重载,以适配不同类型的变量;

2、模板的优劣势

(1)优点:使用模板可以写出更加抽象和简洁的代码;可以将运算逻辑相同只有数据类型不同的函数用模板进行抽象,一个模板函数实现多个重载函数的效果,比如上面的add函数;
(2)缺点:模板并不是必须,不使用模板一样可以实现同样的效果,使用模板需要额外学习和掌握模板编程的规则;
总结:模板编程是用复杂度换取劳动量,用模板写代码抽象度更高,代码简洁,但是对程序员的要求也更高;

3、模板的原理分析

(1)模板编程可以写出类型无关的函数和类,代码更抽象,只关注逻辑部分,编译器在编译模板类/函数时不会指定具体的数据类型;
(2)在使用模板类/函数时,需要指定模板参数的类型,编译器会替换模板参数为具体的类;
(3)在最终编译成的代码中,是没有模板类/函数的,因为编译器已经在用到模板函数/类的地方都替换成了具体的函数类型;
(4)模板是编译器提供的机制,实现了编译时的多态;

4、模板实现运算符重载函数

4.1、示例代码

#include <iostream>
#include <string>

using namespace std;


// 定义模板类
template <typename T> class People
{
private:
	T age;

public:
	People(){};
	People(T a):age(a){};
	
	// 运算符重载 +  -		c = a + b;
	People<T> operator+(People<T> &other);
	
	// 运算符重载+=		a += b;  等价于 a = a + b;
	People<T> operator+=(People<T> &other);
	
	void print(void);
};

//友元函数进行运算符重载
template <typename T> People<T> People<T>::operator+(People<T> &other)
{
	People<T> tmp;
	
	tmp.age = this->age + other.age;
	return tmp;
}

//友元函数进行运算符重载
template <typename T> People<T> People<T>::operator+=(People<T> &other)
{
	this->age += other.age;
	
	return *this;
}

template <typename T> void People<T>::print(void)
{
	cout << "age = " << this->age << endl;
}

int main(void)
{
	//在定义People类的对象时需要指定模板类的具体类型
	People<string> a("hello ");
	People<string> b("word !");
	People<string> c("");

	a += b;
	a.print();
	
	//在定义People类的对象时需要指定模板类的具体类型
	People<int> d(4);
	People<int> e(6);
	People<int> f(0);

	f = d + e;
	f.print();
	
	return 0;
}

4.2、代码分析

[root#]$ ./app 
age = hello word !
age = 10

(1)用友元函数对People类的"+、+="运算符进行重载,并且重载函数也是带模板类的;
(2)在定义People类的对象时,需要指定模板类T的具体类型,这个类型也会传给运算符重载函数,这样类和重载函数的模板类T都被具体的数据类型所代替;
(3)友元函数参考博客:https://blog.csdn.net/weixin_42031299/article/details/127699941;
(4)运算符重载参考博客:https://blog.csdn.net/weixin_42031299/article/details/127593164;

5、模板类的继承

5.1、示例代码

#include <iostream>
#include <string>

using namespace std;


// 定义模板类,作为父类
template <typename U1, typename U2> class People
{
public:
	U1 x1;		// x1是double
	U2 x2;		// x2是int
	
	
	People(){};
	People(U1 a, U2 b):x1(a),x2(b){};
	
};

// Man类里T1对应int,T2对应double
//把T1和T2模板参数传给父类People,去初始化父类的模板参数
template <typename T1, typename T2> class Man:public People<T2, T1>
{
public:
	T1 y1;		// T1 int 
	T2 y2;		// T2 double
	
	Man(){};
	Man(T1 a, T2 b):y1(a),y2(b){};
	
	// 4个参数,顺序:按照y1 y2 x2 x1
	//T1传给People的U2,T2传给People的T1
	Man(T1 a1, T2 a2, T1 b1, T2 b2):People<T2,T1>(b2, b1),y1(a1),y2(a2){};

};

int main(void)
{
	//此时Man类的T1对应int,T2对应double
	Man<int,double> m1(4, 5.5, 6, 7.7);		// y1=4, y2=5.5 	x1=7.7, x2=6
	cout << "x1 = " << m1.x1 << ", x2 = " << m1.x2 << endl;
	cout << "y1 = " << m1.y1 << ", y2 = " << m1.y2 << endl;

	return 0;
}

5.2、代码分析

[root#]$ ./app 
x1 = 7.7, x2 = 6
y1 = 4, y2 = 5.5

(1)首先需要知道在定义模板类时模板参数是未知的,但是在用模板类实例化对象时需要传入模板类的类型,所以模板类都会被具体的类型所替代;
(2)模板类的继承和一般类的继承规则是一样的,区别是继承父类时,父类中模板参数也会继承下来,子类在继承时需要给父类的模板参数指定具体类型,否则父类中的模板参数就还是未知,这样是会报错;

6、非类型模板参数

6.1、示例代码

#include <iostream>
#include <string>

using namespace std;

//非类型模板参数类
//T是类型模板,代表一个未知数据类型
//MAX是整数类型但是值未知,需要在定义模板类的对象时指定
template <typename T, int MAX>
class People
{
public:
	char buffer[MAX];

	T info;

	People(){};
	People(T a)
	{
		info = a;
	}

	void print(void)
	{
		cout << "" << info <<endl;
		cout << "sizeof(buffer) = " << sizeof(buffer) << endl;
	}
};

//非类型模板参数函数
//T是类型模板,代表一个未知数据类型
//VAL是整数类型但是值未知,需要在使用模板函数时指定
template <typename T, int VAL> 
T addValue (T const& x) 
{ 
    return x + VAL; 
}

int main(void)
{
	People<string, 77> p("hello word!"); 
	p.print();

	int a = 11;
	cout << "addValue<int, 22>(a) = " << addValue<int, 22>(a) << endl;

	return 0;
}

6.2、代码分析

[root#]$ ./app 
hello word!
sizeof(buffer) = 77
addValue<int, 22>(a) = 33

(1)非类型模板参数类/函数,顾明思义,模板参数代表的不是数据类型而是某个值;
(2)类型模板参数在示例化时指定数据类型,非类型模板参数在示例化时指定具体的值,思路都是一样的;
(3)非类型模板参数型限制:可以是常整数(包括enum枚举类型)或者指向外部链接对象的指针,但是浮点数和类对象(class-type)不允许作为非类型模板参数:

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
鸡啄米的资料,大家可以上官网看。这是我整理的压缩包,大家可以离线看。(这个资源还要大家积分,实在是惭愧,只因积分不够用,抱歉,体谅!) 大家要是觉得不错,可以下载我整理得另一套资源:VS2010+MFC编程入门,也是鸡啄米的,写得不错,通俗易懂! --------------------------完整目录如下------------------- 第一部分:C++编程概述 鸡啄米:C++编程入门系列之前言 鸡啄米:C++编程入门系列之一(进制数) 鸡啄米:C++编程入门系列之二(原码、反码与补码) 第二部分:C++简单程序设计 鸡啄米:C++编程入门系列之三(VS2010的使用介绍) 鸡啄米:C++编程入门系列之四(数据类型) 鸡啄米:C++编程入门系列之五(运算符和表达式) 鸡啄米:C++编程入门系列之六(算法的基本控制结构之选择结构) 鸡啄米:C++编程入门系列之七(算法的基本控制结构之循环结构) 鸡啄米:C++编程入门系列之八(自定义数据类型) 第三部分:函数 鸡啄米:C++编程入门系列之九(函数定义与调用) 鸡啄米:C++编程入门系列之十(函数的参数传递与内联函数) 鸡啄米:C++编程入门系列之十一(重载函数函数模板) 第四部分:类与对象 鸡啄米:C++编程入门系列之十二(类与对象:面向对象设计的基本思 想和特点) 鸡啄米:C++编程入门系列之十三(类与对象:类的声明、成员的访问 控制和对象) 鸡啄米:C++编程入门系列之十四(类与对象:构造函数和析构函数) 鸡啄米:C++编程入门系列之十五(类与对象:类的组合) 鸡啄米:C++编程入门系列之十六(类与对象:类模板) 鸡啄米:C++编程入门系列之十七(类与对象:UML简介) 第五部分:C++程序设计必知 鸡啄米:C++编程入门系列之十八(C++程序设计必知:作用域和可见 性) 鸡啄米:C++编程入门系列之十九(C++程序设计必知:生存期) 鸡啄米:C++编程入门系列之二十(C++程序设计必知:数据和函数) 鸡啄米:C++编程入门系列之二十一(C++程序设计必知:类的静态成 员) 鸡啄米:C++编程入门系列之二十二(C++程序设计必知:友元) 鸡啄米:C++编程入门系列之二十三(C++程序设计必知:常引用、常对 象和对象的常成员) 鸡啄米:C++编程入门系列之二十四(C++程序设计必知:多文件结构和 编译预处理命令) 第六部分:数组、指针和字符串 鸡啄米:C++编程入门系列之二十五(数组、指针和字符串:数组的声 明和使用) 鸡啄米:C++编程入门系列之二十六(数组、指针和字符串:数组的存 储与初始化、对象数组、数组作为函数参数) 鸡啄米:C++编程入门系列之二十七(数组、指针和字符串:指针变量 的声明、地址相关运算--“*”和“&”) 鸡啄米:C++编程入门系列之二十八(数组、指针和字符串:指针的赋 值和指针运算) 鸡啄米:C++编程入门系列之二十九(数组、指针和字符串:指向数组 元素的指针和指针数组) 鸡啄米:C++编程入门系列之三十(数组、指针和字符串:指针用作函 数参数、指针型函数函数指针) 鸡啄米:C++编程入门系列之三十一(数组、指针和字符串:对象指 针) 鸡啄米:C++编程入门系列之三十二(数组、指针和字符串:动态内存 分配和释放) 鸡啄米:C++编程入门系列之三十三(数组、指针和字符串:用字符数 组存放和处理字符串) 鸡啄米:C++编程入门系列之三十四(数组、指针和字符串:string 类) 第七部分:继承与派生 鸡啄米:C++编程入门系列之三十五(继承与派生:概念介绍与派生类 的声明) 鸡啄米:C++编程入门系列之三十六(继承与派生:派生类从基类继承 的过程) 鸡啄米:C++编程入门系列之三十七(继承与派生:派生类对基类成员 的访问控制之公有继承) 鸡啄米:C++编程入门系列之三十八(继承与派生:派生类对基类成员 的访问控制之保护继承与私有继承) 鸡啄米:C++编程入门系列之三十九(继承与派生:派生类的构造函 数) 鸡啄米:C++编程入门系列之四十(继承与派生:派生类的析构函数) 鸡啄米:C++编程入门系列之四十一(继承与派生:作用域分辨符) 鸡啄米:C++编程入门系列之四十二(继承与派生:虚基类及其派生类 的构造函数) 鸡啄米:C++编程入门系列之四十三(继承与派生:赋值兼容规则) 第八部分:多态性 鸡啄米:C++编程入门系列之四十四(多态性:多态的概念和类型) 鸡啄米:C++编程入门系列之四十五(多态性:运算符重载的概念和规 则) 鸡啄米:C++编程入门系列之四十六(多态性:运算符重载为类的成员 函数) 鸡啄米:C++编程入门系列之四十七(多态性:运算符重载为类的友元 函数) 鸡啄米:C++编程入门系列之四十八(多态性:虚函数) 鸡啄米:C++编程入门系列之四十九(多态性:纯虚函数和抽象类) 第九部分:异常处理 鸡啄米:C++编程入门系列之五十(异常处理) 鸡啄米:C++编程入门系列之目录和总结

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

正在起飞的蜗牛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值