栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++提高编程——模板

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++提高编程——模板

目录

一、函数模板的使用

一、使用方法

二、用模板实现选择排序

三、普通函数与函数模板的区别

四、普通函数与函数模板的使用规则 

五、函数模板的局限性

二、类模板的使用

 一、使用方法

二、类模板成员对象创建时机

三、类模板传参

四、类模板与继承

五、类模板成员函数类外实现

六、类模板的分文件编写

七、类模板与友元

八、实例-模板数组


模板属于C++的泛型编程,它通过建立通用模板,大大提高了代码复用性

一、函数模板的使用

一、使用方法

先声明模板的虚拟类型

template

 后面紧跟着函数声明或定义,其参数类型用T替换

如交换函数

#include
using namespace std;
template
void Tswap(T&x, T&y)
{
	T ret = x;
	x = y;
	y = ret;
}
int main()
{
	int a = 10, b = 20;
	double c = 3.1415926, d = 2.7141;
	cout << "a=" << a << ",b=" << b << endl;
	Tswap(a, b);
	cout << "a=" << a << ",b=" << b << endl;
	cout << "c=" << c << ",c=" << d << endl;
	Tswap(c, d);
	cout << "c=" << c << ",c=" << d << endl;
	return 0;
}

 可以看到,通过模板,交换函数能实现对不同数据类型的交换,使用时,可以直接传参赋值,编译器会自动推导类型,但两个数的类型必须相同,也可以指明数据类型。

#include
using namespace std;
template
void Tswap(T1&x, T2&y)
{
	T1 ret = x;
	x = y;
	y = ret;
}
int main()
{
	int a = 10, b = 20;
	double c = 3.1415926, d = 2.7141;
	cout << "a=" << a << ",c=" << c << endl;
	Tswap(a, c);
	cout << "a=" << a << ",c=" << c << endl;
	cout << "b=" << b << ",d=" << d << endl;
	Tswap(b, d);
	cout << "b=" << b << ",d=" << d << endl;
	return 0;
}

模板参数类型声明可用typename,也可以用class,多个不同类型,可以声明多个虚拟参数来实现自动类型推导。

 模板必须要确定数据类型才能使用

#include
using namespace std;
template
void func()
{
	cout << "this is a function" << endl;
}
int main()
{
	func();
}

fun即使不传参,也要指明数据类型才能使用 

二、用模板实现选择排序
#include
using namespace std;
template
void TSort(T*a,int len)
{
	for (int i = 0; i < len; i++)
	{
		int min = i;
		for (int j = i + 1; j < len; j++)
			if (a[min] > a[j])
				min = j;
		if (min != i)
		{
			T ret = a[min];
			a[min] = a[i];
			a[i] = ret;
		}
	}
}
template
void PrintArray(T*a, int len)
{
	for (int i = 0; i < len; i++)
		cout << a[i] << " ";
	cout << endl;
}
int main()
{
	int a[] = { 3,4,7,1,2,8,9,10,4,6 };
	char c[] = "qwerttyuiop";
	TSort(a,sizeof(a)/sizeof(a[0]));
	TSort(c, sizeof(c) / sizeof(c[0])-1);//''不能参与排序
	PrintArray(a, sizeof(a) / sizeof(a[0]));
	PrintArray(c, sizeof(c) / sizeof(c[0]));//''要打印出来
	return 0;
}

其实就是原封不动,将数据类型换成了T,可以看到,不同类型的数据可以共有这一个函数实现功能,这便是模板的意义,提高代码利用率。 

三、普通函数与函数模板的区别

普通函数可以发生隐式类型转化,而函数模板在自动类型推导的情况下无法发生隐式类型转化,在显示指定类型的情况下可以发生隐式类型转化。

#include
using namespace std;
template
void Print(T a,T b)
{
	cout << "a+b=" << a + b << endl;
}
int main()
{
	int a = 10;
	char b = 'a';
	//Print(a, b);不行无法隐式类型转化
	Print(a, b);//会把b转化为int类型
	Print(a, b);//会把a转化为char类型,打印出来的仍为ascii码值
	return 0;
}

四、普通函数与函数模板的使用规则 

1.如果普通函数和函数模板都可以实现这一功能,优先使用普通函数、

2.可以通过空模板参数列表强制调用模板

3.函数模板也能发生重载

4.如果函数模板能产生更好的匹配

#include
using namespace std;
void Print(int a, int b)
{
	cout << "调用普通函数" << endl;
}
template
void Print(T a, T b)
{
	cout << "调用函数模板" << endl;
}
template
void Print(T a, T b, T c)
{
	cout << "调用重载的函数模板" << endl;
}
int main()
{
	int a = 10, b = 10;
	char c1 = 'a', c2 = 'b';
	Print(a, b);//调用普通函数
	Print<>(a, b);//调用函数模板
	Print(a, b, 100);//调用重载的函数模板
	Print(c1, c2);//调用函数模板
	return 0;
}

如果提供了函数模板,最好不要创建普通函数,以免调用出错。

五、函数模板的局限性

对于自定义的数据类型,如类和结构体,编译器无法识别并完成比较,运算等操作。

解决办法有两个,一个是运算符重载,二是模板重载

#include
using namespace std;
class Person
{
public:
	int age;
	int money;
};
template
T Add(T&a, T&b)
{
	return a + b;
}
Person&operator+(Person&a,Person&b)
{
	Person*temp = new Person;
	temp->age = a.age+b.age;
	temp->money = a.money + b.money;
	return *temp;
}
template
bool compare(T&a, T&b)
{
	return a == b;
}
template<> bool compare(Person&a, Person&b)
{
	return a.age == b.age&&a.money == b.money;
}
int main()
{
	Person p1 = { 12,1 }, p2 = { 12,1 }, p3;
	if (compare(p1, p2))
		cout << "p1==p2" << endl;
	else
		cout << "p1!=p2" << endl;
	p3 = Add(p1, p2);
	cout << "age=" << p3.age < 

 对模板的学习并不是为了写模板,而是学会使用STL中系统提供的模板

二、类模板的使用

 一、使用方法

使用类模板必须使用参数列表指明数据类型,不能自动类型转化

#include
#include
using namespace std;
template//默认Age为int类型·
class Person
{
public:
	Name m_name;
	Age m_age;
	Person(Name name, Age age)
	{
		this->m_age = age;
		this->m_name = name;
	}
	void show()
	{
		cout << this->m_name << " "<< this->m_age << "岁" << endl;
	}
};
int main()
{
	Personp( "齐天大圣", 1000 );
	Personq("艾伦*耶格尔", 20);
	p.show();
	q.show();
	return 0;
}

仅在类模板中模板参数列表可以赋默认值

二、类模板成员对象创建时机
#include
using namespace std;
class A
{
public:
	void showA()
	{
		cout << "this is class A" << endl;
	}
};
class B
{
public:
	void showB()
	{
		cout << "this is class B" << endl;
	}
};
template
class C
{
public:
	T obj;
	void show1()
	{
		obj.showA();
	}
	void show2()
	{
		obj.showB();
	}
};
int main()
{
	Cc1;
	c1.show1();
	Cc2;
	c2.show2();
	return 0;
}

成员对象是在确定了参数模板里的数据类型后创建的,只能调用模板参数类型对应的类中函数

三、类模板传参

类模板传参又三种方法,第一种常用

#include
#include
using namespace std;
template
class Person
{
public:
	Name m_name;
	Age m_age;
	Person(Name name, Age age)
	{
		this->m_name = name;
		this->m_age = age;
	}
	void showinfo()
	{
		cout << "姓名:" << this->m_name << " 年龄:" << this->m_age << endl;
	}
};

//第一种:指定传入类型
void fun1(Person&p)
{
	p.showinfo();
}
//第二种:参数模板化
template
void fun2(Person&p)
{
	p.showinfo();
	cout << typeid(T1).name() << endl << typeid(T2).name() << endl;
}
//第三种:整个类模板化
template
void fun3(T&p)
{
	p.showinfo();
	cout << typeid(T).name() << endl;
}
int main()
{
	Personp("艾伦*耶格尔", 21);
	fun1(p);
	fun2(p);
	fun3(p);
	return 0;
}

typeid(模板参数).name(),可显示·参数变量的全名。

四、类模板与继承

当子类继承的父类是一个类模板时,必须指定父类中T的类型,如果想灵活的指定父类中T的类型,子类也需要变为类模板。

#include
using namespace std;
template
class A
{
public:
	T m;
};
class B :public A
{

};
template
class C :public A
{
public:
	T2 obj;
	void showname()
	{
		cout << typeid(T1).name() << endl << typeid(T2).name() << endl;
	}
};
int main()
{
	B b;
	Cc;
	c.showname();
	return 0;
}

第一种是在子类继承父类的后面加一个参数列表,指定对应的模板参数类型。

第二种,将子类也设为类模板,设置子类自身以及父类的参数模板类型。

五、类模板成员函数类外实现
#include
#include
using namespace std;
template
class Person
{
public:
	T1 name;
	T2 age;
	Person(T1 name, T2 age);
	void showinfo();
};
template
Person::Person(T1 name, T2 age)
{
	this->age = age;
	this->name = name;
}
template
void Person::showinfo()
{
	cout<<"姓名:" << this->name << " 年龄:" << this->age << endl;
}
int main()
{
	Personp("艾伦*耶格尔", 21);
	p.showinfo();
	return 0;
}

六、类模板的分文件编写

由于类模板成员函数是在调用阶段才创建,分文件编写,会导致链接不到。

有两种解决办法。一、引用cpp做头文件,因为cpp里引用了.h的头文件。

二、将类的声明与实现写在一个文件中,并命名为.hpp。

七、类模板与友元
#include
#include
using namespace std;
template
class Person;
template
void showinfo2(Person&p)
{
	cout << "类外实现——姓名:" << p.m_name << " 年龄" << p.m_age<
class Person
{
	friend void showinfo1(Person&p)
	{
		cout << "类内实现——姓名:" << p.m_name << " 年龄" << p.m_age << endl;;
	}
	friend void showinfo2<>(Person&p);
public:
	Person(T1 name, T2 age)
	{
		this->m_age = age;
		this->m_name = name;
	}
private:
	T1 m_name;
	T2 m_age;
};
int main()
{
	Personp("艾伦*耶格尔", 21);
	showinfo1(p);
	showinfo2(p);
	return 0;
}

类内友元比较好写,类外友元要写在friend 声明之前。且friend声明要用空参数列表标识其为模板,然后要声明Person类模板。

八、实例-模板数组
#include
#include
using namespace std;
template
class Array
{
	T*base;
	int capacity;
	int size;
public:
	//构造函数
	Array(int n)
	{
		this->capacity = n;
		this->base = new T[this->capacity];
		this->size = 0;
	}
	//拷贝构造,注意深拷贝
	Array(const Array&a)
	{
		this->capacity = a.capacity;
		this->size = a.size;
		this->base = new T[this->capacity];
		for (int i = 0; i < this->size; i++)
			this->base[i] = a.base[i];
	}
	Array&operator=(const Array&a)
	{
		if (this->base)
		{
			delete[]this->base;
			this->base = NULL;
			this->capacity = 0;
			this->size = 0;
		}
		this->capacity = a.capacity;
		this->size = a.size;
		this->base = new T[this->capacity];
		for (int i = 0; i < this->size; i++)
			this->base[i] = a.base[i];
		return *this;
	}
	//尾插
	void Push_Back(const T&a)
	{
		if (this->capacity == this->size)
			return;
		this->base[this->size++] = a;
	}
	//尾删
	void Pop_Back()
	{
		if (this->size == 0)
			return;
		this->size--;
	}
	T&operator[](int index)
	{
		return this->base[index];
	}
	int Size()
	{
		return this->size;
	}
	int Capacity()
	{
		return this->capacity;
	}
	~Array()
	{
		if (this->base)
		{
			delete []base;
			base = NULL;
		}
	}
};
int main()
{
	Arraya(10);
	for (int i = 0; i < 10; i++)
		a.Push_Back(i);
	while (a.Size()>0)
	{
		cout << a[a.Size() - 1] << " ";
		a.Pop_Back();
	}
	cout << endl;
	Arrayc(10);
	for (int i = 97; i < 107; i++)
		c.Push_Back(i);
	Arraycc(c);
	while (c.Size() > 0)
	{
		cout << c[c.Size() - 1] << " ";
		c.Pop_Back();
	}
	cout << endl;
	for (int i = 0; i < cc.Size(); i++)
		cout << cc[i] << " ";
	cout << endl;
}

自定义实现不同数据类型的数组,这便是STL容器所应用的,模板栈,模板队列....

看到这,点个赞再走吧

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/989526.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号