07 模板

模板

学习目的:

  1. 了解并理解模板的概念;
  2. 熟悉函数模板的使用;
  3. 熟悉类模板的使用;

​ 通过模板的使用最大化代码的重用

内容:

模板概念 函数模板(** ) 类模板(** ) 模板与友元

模板的概念

模板与泛型编程:

  1. 泛型编程:编写与类型无关的逻辑代码(只关注代码逻辑,不关注类型)
  2. 模板:实现代码重用的一种工具或方法,作用是实现类型参数化(类型可以作为参数进行传递)

模板是实现泛型编程的先决条件。

模板分类:

  1. 函数模板:是模板的一种,可以用函数模板定义出模板函数
  2. 类模板:是模板的一种,可以用类模板定义出模板类

函数模板

模板函数:用函数的模板写出来的模板函数,数据类型需要通过参数传进来,在此之前模板函数是不完整的,编译器不会将其生成可执行代码。

语法:

// 通过 函数模板 定义 模板函数
template <typename Type_1, ..., typename Type_n>
返回值类型 函数名(形参列表)
{
    函数体;
}

// 示例
template <typename T1, typename T2>
T1 add(T1 a, T2 b)
{
    return a+b;
}

// typename 也可以换成 class
template <class TT1, class TT2>
void test(TT1 tt1, TT2 tt2)
{
    cout<<"tt1 = "<< tt1 << endl
     	<<"tt2 = "<< tt2 << endl;
}

// 调用
函数名<类型列表>(实参表)

模板函数调用:

#include <iostream>
using namespace std;

template<typename Type>
Type add(Type a, Type b)
{
	return a + b;
}

template <class TT1, class TT2>
void test(TT1 tt1, TT2 tt2)
{
	cout << "tt1 = " << tt1 << "\t\t"
		<< "tt2 = " << tt2 << endl;
}


int	main()
{
	// 隐式调用
	cout << "******** 隐式调用 *********" << endl;
	test(1, 2);
	test(1.123, 2.246);
	test("name", 'S');

	cout << add(3, 4) << endl;
	// 编译器报错(类型推到错误)
	// cout << add(2.14, 4) << endl;

	
	// 类型传输	函数名<类型列表>(实参表)
	cout << "******** 显示调用 *********" << endl;
	cout << add<int>(2.14, 4) << endl;
	cout << add<double>(2.14, 4) << endl;

	cout << "*****************" << endl;
	test<const char*, char>("Hello", 'C');

	return 0;
}

输出:

在这里插入图片描述
函数模板和普通函数:

  1. 和普通函数一样也可以构成重载;
  2. 普通函数和模板函数构成重载的情况下,优先调用普通函数;
  3. 强制调用模板函数,显示调用即可;

模板的局限性:

对于自定义的类,可以通过重载函数进行解决

#include <iostream>
using namespace std;

class MyData
{
public:
	MyData(int n = 0) : num(n){}
	int num;

};


template <typename T>
bool func(const T & a,const T & b)
{
	return (a == b ? true : false);
}

// 重载一次函数用于比较自定义类的对象
template<> bool func(const MyData & obj1, const MyData & obj2)
{
	return(obj1.num == obj2.num ? true : false);
}


int	main()
{
	int num, val;
	num = 8;
	val = 8;
	
	cout << ( func(num, val) ? "true" : "false" ) << endl;
	cout << (func<int>(num, val) ? "true" : "false") << endl;

	MyData obj_0, obj_2(5);	// 也可以重载"=="用于比较自定义的类
	cout << (func(obj_0, obj_2) ? "true" : "false") << endl;
	cout << (func<MyData>(obj_0, obj_2) ? "true" : "false") << endl;


	return 0;
}

输出:

在这里插入图片描述

类模板

与函数模板类似,所定义的模板类一样是不完整的类。

语法:

template <类型参数列表>
class 模板类名
{
    成员;
};

类型参数列表:<class Type1, ..., class Type2>

示例:

#include <iostream>
using namespace std;

//template <class Type1, class Type2>
template <class Type1 = int, class Type2 = double>	// 类型参数缺省必须从后往前
class MyData
{
public:
	MyData(Type1 n = 0, Type2 v = 1.0);
	Type1 getNum() { return num; }
	Type2 getVal() { return val; }
	void setNum(Type1 n);
	void setVal(Type2 v) { val = v; }

	// 类外实现
	void showData();

private:
	Type1 num;
	Type2 val;

};

// 构造函数必须与模板类的类型名定义方式相同
template <class Type1, class Type2>
MyData<Type1, Type2>::MyData(Type1 n, Type2 v) : num(n), val(v)
{
}

// 类外定义带参数的函数时,也需要与模板类的类型名定义方式相同(不相同应该也可以,这块儿的逻辑没盘明,需进一步了解学习)
template <class Type1, class Type2>
void MyData<Type1, Type2>::setNum(Type1 n)
{
	num = n;
}

// 此处类型的定义方式就与模板类的名字不同
template <typename T1, typename T2>
void MyData<T1, T2>::showData()
{
	cout << "num = " << num << "  val = " << val << endl;
}

int	main()
{
	MyData<> data_1(3, 3.14);
	data_1.showData();

	MyData<char> data_2(65, 5.5);
	data_2.showData();

	return 0;
}

输出:在这里插入图片描述

类模板做函数的参数(多种不同的方式)

#include <iostream>
using namespace std;


//template <class Type1, class Type2>
template <class Type1 = int, class Type2 = double>	// 类型参数缺省必须从后往前
class MyData
{
public:
	MyData(Type1 n = 0, Type2 v = 1.0);
	Type1 getNum() { return num; }
	Type2 getVal() { return val; }
	void setNum(Type1 n);
	void setVal(Type2 v) { val = v; }

	// 类外实现
	void showData();

private:
	Type1 num;
	Type2 val;

};

// 构造函数必须与模板类的类型名定义方式相同
template <class Type1, class Type2>
MyData<Type1, Type2>::MyData(Type1 n, Type2 v) : num(n), val(v)
{
}

// 类外定义带参数的函数时,也需要与模板类的类型名定义方式相同(不相同应该也可以,这块儿的逻辑没盘明,需进一步了解学习)
template <class Type1, class Type2>
void MyData<Type1, Type2>::setNum(Type1 n)
{
	num = n;
}

// 此处类型的定义方式就与模板类的名字不同
template <typename T1, typename T2>
void MyData<T1, T2>::showData()
{
	cout << "num = " << num << "  val = " << val << endl;
}

// 类模板作为函数的参数 法一
void testFunc_1(MyData<int, double>& obj)
{
	obj.showData();
}

// 类模板作为函数的参数 法二:写成函数模板的形式
template <typename TT1,typename TT2 = double>	// TT2可缺省
void testFunc_2(MyData<TT1, TT2>& obj)
{
	obj.showData();
}

// 类模板作为函数的参数 法三:将类作为类型
template <class ClassType>
void testFunc_3(ClassType& obj)
{
	obj.showData();
}

int	main()
{
	MyData<> data_1(3, 3.14);
	testFunc_1(data_1);

	cout << "***********************" << endl;
	MyData<char> data_2(65, 5.5);
	MyData<int, double>data_3(65, 5.5);
	testFunc_2(data_2);
	testFunc_2<char, double>(data_2);
	testFunc_2<int, double>(data_3);

	cout << "***********************" << endl;
	testFunc_3(data_2);		// 隐式调用
	testFunc_3(data_3);
	// 两层<> 是正确的,理解并熟悉		
	testFunc_3<MyData<char,double>>(data_2);	// 显示调用


	return 0;
}

输出:
在这里插入图片描述

类模板和继承

#include <iostream>
using namespace std;

template <class F_Type>
class Father
{
public:
	F_Type m_F_val;
};

// 子类继承时指定父类模板的参数类型即可
class Son : public Father<double>
{
public:
	int m_S_val;
};

// 子类也定义成模板的形式
template <class S_Type1, class S_Type2>
class Son_1 : public Father<S_Type1>
{
public:
	S_Type2 m_S_val1;

};



int	main()
{
	Son_1<int, double>obj_son;
	obj_son.m_F_val = 1;
	obj_son.m_S_val1 = 2;

	return 0;
}

注(***):

类模板的声明和成员函数的实现要写在同一个文件里面;

文件后缀名为".hpp";

模板和友元

注释有很多需要注意的地方:

#include <iostream>
using namespace std;

template <class T = int>
class A;

template <typename Type>
void show_2(A<Type>& obj);	// 声明show_2()时,类A不认识,因此也需要对class A 进行一次声明

template <class T = int>
class A
{
public:
	A(T t = 0) : m_a(t){}


	// 1、类体里定义友元函数
	friend void show_1(A<T>& obj)
	{
		cout << obj.m_a << endl;
	}

	// 2、类外实现
	friend void show_2<>(A<T>& obj);	// 声明时在函数名的后面加上<>,表示其为模板类的友元(***)

private:
	T m_a;
};


// 因为编译器不认识 show_2() 因此需要在最上面对其进行一次声明;
template <typename Type>
void show_2(A<Type>& obj)
{
	cout << obj.m_a << endl;
}



int	main()
{
	A<int> obj_a(666);
	show_1(obj_a);

	show_2(obj_a);

}

<未完待续>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值