c++模板(函数模板,类中函数模板,类模板)

作用:

减少程序中的冗余信息。如:多个函数或类的除了参数类型外,其余都完全相同时,可以使用模板来减少重复信息(参考函数重载时,输入参数数量也相同的情况)

1、函数模板

即建立一个通用函数,只不过该函数的返回类型和形参类型都不具体指定,其定义格式如下:

template <typename 类型名>

类型名或void  函数名(类型名 形参表)

{

        函数体

}

template <class 类型名>

类型名或void  函数名(类型名 形参表)

{

        函数体

}

1、此处的类型名是由开发人员自己决定的。 

2、一般不注重向后兼容且愿意输入较长的类型名时,选用typename。

代码示例:

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

template <typename ty_na>
ty_na func_name(ty_na* parameters, int size = 0) {
	ty_na first_num = parameters[size];
	return first_num;
}

int main()
{
	int array_int[] = {1,2,3,4,5};
	int first_num = func_name(array_int, 0);
	cout << first_num << endl;
	return 0;
}

此外,由于函数模板也属于函数,因此也可以对其进行函数重载,重载时,参数和参数数量均可改变:

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

template <class type>
type func_name2(type a, type b)
{
	type c = a - b;
	return c;
}

template <class type>
type func_name2(type x, type b, type k)
{
	type y = k * x + b;
	return y;
}
int main()
{
	int get_c = func_name2(1, 2);
	double get_y = func_name2(2.0, 3.2, 2.0);
	cout << "get_c=" << get_c << endl;
	cout << "get_y=" << get_y << endl;
}

2、类中函数模板

2.1先在头文件的对应类中声明模板函数

class cls1
{
public:
    template<typename T>
    void func(T &args);
}

2.2在对应cpp文件中定义模板函数

    template<typename T>
    void cls1::func(T &args)
    {
        函数体
    }

3、类模板

3.1 基本概念

格式:

template <template 类型名>

class 类名

{

public:

        类型名 成员数据

        成员函数(函数类型名 参数名)

}

 当类模板中的成员函数需要在类外定义时,格式为:

template <typename 类型名>

函数类型名 类名<类型名>::成员函数名(类型名 形参表) {...}

 示例:

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

template <typename num>
class compute
{
public:
	num a, b;
	compute(num x, num y) :a(x), b(y) {};
	num add();
};
template <typename num>
num compute<num>::add(){
	return a + b;
}

int main()
{
	compute<int> result(2, 3);
	cout << result.add() << endl;
}

 此外,类模板可以对模板类型指定默认类型,如:

template <typename TYPE=int>

class CLS{...}

         注意:必须使用显示类型指导调用类模板进行实例化,否则类模板无法识别类型。当类模板有类型默认参数时,可以不实例化对应类型。

template <class Name_T,class Age_T = int>
class Person {
public:
	Person(Name_T name, Age_T age) {
		this->m_Name = name;
		this->m_Age = age;
	}
	void showPerson() {
		cout << "name:" << this->m_Name << " ";
		cout << "age:" << this->m_Age << endl;
	}

private:
	Name_T m_Name;
	Age_T m_Age;
};

int main() {

	//Person p1("马蒂", 22);

	//使用显示类型指导调用类模板进行实例化,否则类模板无法识别类型
	Person<string, int> p1("马蒂", 22);
	p1.showPerson();

	Person<string> p2("诺顿", 78);//当类模板有类型默认参数时,可以不实例化对应类型
	p2.showPerson();
	system("pause");
	return 0;
}

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

        一般类中的成员函数是一开始就创建,而类模板中的成员函数在调用时才会被创建

如:下列代码可以生成成功,但在实际运行时必定会报错,这是因为类模板的成员函数在生成时并没有被创建,而发生调用后,才能被编译器检查到是否调用发生错误。

class P1 {
public:
	void func1() {
		cout << "P1" << endl;
	}
};

class P2 {
public:
	void func2() {
		cout << "P2" << endl;
	}
};

template <class T>
class TP {
public:
	T obj;
	void func3() {
		obj.func1();
	}

	void func4() {
		obj.func2();
	}
};

int main() {

	TP<P1> p1{};
	p1.func3();
	p1.func4();
	system("pause");
	return 0;
}

 3.3类模板实例化的对象作为函数参数

        a)指定传入的类型,直接显示对象的数据类型。

        b)对象中的参数变成模板传入。

        c)整个类模板化,将对象类型模板化进行传递。

template <class Name_T,class Age_T = int>
class Person {
public:
	Person(Name_T name, Age_T age) {
		this->m_Name = name;
		this->m_Age = age;
	}
	void showPerson() {
		cout << "name:" << this->m_Name << " ";
		cout << "age:" << this->m_Age << endl;
	}

private:
	Name_T m_Name;
	Age_T m_Age;
};

//指定传入的类型,直接显示对象的数据类型。
void func1(Person<string, int>& p) {
	p.showPerson();
}
//将对象中的参数变成模板传入。
template<class T1, class T2>
void func2(Person<T1, T2>& p) {
	p.showPerson();
}
//整个类模板化,将对象类型模板化进行传递。
template<class T_>
void func3(T_& p) {
	p.showPerson();
}

4、多类型模板

当需要返回的值的类型不确定时,可声明返回类型为auto(c++11),此时需要在函数体内使用decltype函数来获取返回值类型:

decltype(计算表达式)  self_typename

 示例:

auto Quick_func::get_max(T1& a, T2& b){
	decltype(a > b ? a : b) out = a > b ? a : b;
	cout << "out:" << out << endl;
	return out;
}


int main()
{
    int a = 20;
	double b = 115.0;
	typedef decltype(a > b ? a : b) outtype;
	outtype out = get_max(a, b);

}

5、类模板与继承

        a)如果父类是类模板,子类必须指定父类的参数类型。

        b)如果想要同样灵活使用的父类的参数,将子类定义为类模板,指定子类的参数类型,将其作为继承到的父类参数类型即可。

        示例:

template <class T>
class Base {
	T num;
};

//指定子类的参数类型
class Son1 :public Base<float> {

};

//灵活使用模板参数
template<class T1,class T2> 
class Son2 :public Base<T1> {
	T2 son2_param;
};

6、类模板成员函数类外实现与分文件编写

6.1 定义

        类外实现:

        当类模板的成员函数在类内声明,类外进行实现时,在实现部分中,必须加上类模板同样的template类型定义行,在普通类成员函数作用域的加上显示自定义类型使用,如:

template<class T>

void 类名<T>::函数名(T 形参)

{...}

        分文件编写 :

        由于类模板中的成员函数是在调用时才会生成,因此如果只include写有类模板成员函数声明的头文件会报错,无法链接到成员函数定义。

        解决方法:

        a)直接在调用该成员函数的文件中包含写有类模板成员函数定义的cpp文件

        b)将类模板成员函数定义和声明写在同一个文件中,并将文件后缀改为hpp

6.2 示例 

头文件:

template <class Name_T,class Age_T>
class Person {
public:
	Person(Name_T name, Age_T age);
	void showPerson();
private:
	Name_T m_Name;
	Age_T m_Age;
};

 函数声明文件:

#include "head1.h"

template<class Name_T,class Age_T>
Person<Name_T, Age_T>::Person(Name_T name, Age_T age) {
	this->m_Name = name;
	this->m_Age = age;
}

template <class Name_T, class Age_T>
void Person<Name_T, Age_T>::showPerson() {
	cout << "name:" << this->m_Name << " ";
	cout << "age:" << this->m_Age << endl;
}

main函数文件:

#include "head1.h"
#include "func1.cpp"
int main() {

	Person<string, int>* p = NULL;
	p = new Person<string, int>("Adam", 23);
	p->showPerson();
	delete p;
	system("pause");
	return 0;
}

7、类模板友元

        a)类模板中可以定义友元全局函数,从而直接使用类模板的自定义数据类型。

        b)当只在类模板中声明友元全局函数时,由于编译顺序原因,需要把该友元全局函数定义在类模板的前面,才能让类模板中的友元声明实现,而与此同时,由于友元全局函数定义时,将类模板作为传入参数,需要在该函数定义前“声明”一下有该类模板的存在,否则不能完成函数定义。

template <class Name_T, class Age_T>
class Person;

template <class T1, class T2>
void printPerson2(Person<T1, T2>& p) {
	cout << "name:" << p.m_Name << " ";
	cout << "age:" << p.m_Age << endl;
}

template <class Name_T,class Age_T>
class Person {
	//类内友元
	friend void printPerson1(Person<Name_T, Age_T> &p) {
		cout << "name:" << p.m_Name << " ";
		cout << "age:" << p.m_Age << endl;
	}
	//类外实现友元
	template <class T1, class T2>
	friend void printPerson2(Person<T1, T2>& p);
public:
	Person(Name_T name, Age_T age);
	void showPerson();
private:
	Name_T m_Name;
	Age_T m_Age;
};

  • 6
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值