C++——模板

C++另一种编程思想泛型编程;
C++提供两种模板机制:
函数模板和类模板;

函数模板的作用:
建立一个通用函数,其函数返回值类型和形参类型可以不具体指定,用一个虚拟的类型来代替;
语法:
template
函数
template–声明创建模板;
T–通用的数据类型,名称可以替换,通常为大写字母;

模板使用是可以有两种使用方法:
自动类型推导(所使用的的数据类型必须要一致);
显示指定类型;

#include <iostream>

using namespace std;

template<typename T>   //声明一个模板,typename可以替换成class

void swapdata(T &a, T &b)
{
	T temp = a;
	a = b;
	b = temp;
}

int main()
{
	int a = 10;
	int b = 20;

	double c = 0.2;
	double d = 0.4;
	//自动类型推导方式使用模板
	swap(a, b);
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;

	//显示指定类型
	swap<double>(c, d);
	cout << "c = " << c << endl;
	cout << "d = " << d << endl;

	system("pause");
	return 0;
}

数组排序:

#include <iostream>

using namespace std;

template<class T>
void myswap(T&a, T&b)
{
	T  temp;
	temp = a;
	a = b;
	b = temp;
}

template<class T>
void mysort(T a[],int num)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < num; i++) {    //选择排序法
		int Max = i;
		for (j = i + 1; j < num;j++ ) {
			if (a[j] > a[Max]) {
				Max = j;
			}
		}
		if (Max != i) {
			//交换max和i元素
			myswap(a[Max], a[i]);
		}
	}
	
}

template<class T>
void print(T a[], int len) {
	int i = 0;
	for (i = 0; i < len; i++) {
		cout << a[i] << " ";
	}
	cout << endl;
}


void test01()
{
	//字符数组测试
	char c[] = "abcdef";
	int size = sizeof(c) / sizeof(char);
	mysort(c, size);
	print(c, size);
}

void test02()
{
	//整数数组测试
	int arr[] = { 2,1,4,5,3,6,7,9,8,0 };
	int size = sizeof(arr) / sizeof(int);
	mysort(arr, 10);
	print(arr, size);

}

int main()
{
	test01();
	test02();

	system("pause");
	return 0;
}

普通函数和函数模板的区别:
普通函数调用时可以发生自动类型转换(隐式类型转换);
函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换(例如普通函数在做int+char时会将char转换为ASCII码);
如果利用显示指定类型的方式,可以发生隐式类型转换;

普通函数和函数模板调用规则:
调用规则如下:
1.如果函数模板和普通函数都可以实现,优先调用普通函数;
2.可以通过空模板参数列表来强制调用函数模板;
3.函数模板也可以发生重载;
4.如果函数模板可以产生更好的匹配,优先调用函数模板;
但是使用了普通函数就不要使用函数模板,避免出现二义性;

#include <iostream>

using namespace std;

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

template<class T>
void fun(T a,T b) {
	cout << "调用模板" << endl;
}

template<class T>
void fun(T a, T b ,T c) {
	cout << "调用重载的模板" << endl;
}


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

	//fun(a, b);     //优先调用的是普通函数

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

	//调用重载模板
	//fun(a,b,100);

	//函数模板产生更好的匹配(虽然可以使用普通函数对其进行转换,但是编译器认为模板更为匹配)
	char c = 'c';
	char d = 'd';
	fun(c, d);


}

int main()
{
	test();
	system("pause");
	return 0;
}

模板的局限性:
有些特定的数据类型需要具体化的方式做特殊实现;

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

class person {

public:
	int m_age;
	string m_name;
};

template <class T>
bool myCompare(T &a, T &b) {
	if (a == b) {
		return true;
	}
	else {
		return false;
	}
}

template<> bool myCompare(person &p1, person &p2)   //具体化myCompare函数中形参的类型;
{
	if (p1.m_age == p2.m_age && p1.m_name == p2.m_name) {
		return true;
	}
	else {
		return false;
	}
}

void test() {
	person p1 = { 10,"ming" };
	person p2 = { 20,"ming" };

	bool ret = myCompare(p1, p2);

	if (ret) {
		cout << "一样" << endl;
	}
	else {
		cout << "不一样" << endl;
	}
}



int main()
{
	test();

	system("pause");
	return 0;
}

类模板:
作用:建立一个通用类,类中的成员,数据类型可以不具体制定,用一个虚拟类型代表;
语法个模板函数一样;
Template

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

template<class Nametype,class Agetype>
class person {
public:
	person(Nametype name, Agetype age) {
		this->m_age = age;
		this->m_name = name;
	}

	void showinfo() {
		cout << "name is:" << m_name << endl;
		cout << "age is:" << m_age << endl;
	}

	Nametype m_name;
	Agetype m_age;
};

void test()
{
	person<string,int>p1("cao", 24);
	p1.showinfo();
	
}


int main()
{
	test();

	system("pause");
	return 0;

}

类模板和函数模板区别:
1.类模板没有自动类型推导的使用方式;
2.类模板在模板参数列表中可以有默认参数;

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

template<class Nametype,class Agetype = int >   //默认第二个参数为整型
class person {
public:
	person(Nametype name, Agetype age) {
		this->m_age = age;
		this->m_name = name;
	}

	void showinfo() {
		cout << "name is:" << m_name << endl;
		cout << "age is:" << m_age << endl;
	}

	Nametype m_name;
	Agetype m_age;
};

void test()
{
	//person p2("cao", 20);  类模板不能自动推导类型
	person<string>p1("cao", 24); //因为在创建类模板时将第二个参数设置为默认参数整型,所以不会报错
	p1.showinfo();
	
}


int main()
{
	test();

	system("pause");
	return 0;

}

类模板中成员函数创建时机:
普通类中成员函数一开始就可以创建
类模板中的成员函数在调用时才创建

类模板做函数参数:
传入方式:
1.指定传入的类型 --直接显示对象的数据类型(最常用);
2.参数模板化 --将对象中的参数变为模板进行传递;
3.整个类模板化 --将这个对象类型模板化进行传递;

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

template<class T1,class T2>
class person {
public:
	person(T1 name,T2 age) {
		this->m_age = age;
		this->m_name = name;
	}

	void showinfo() {
		cout << "age is " << this->m_age << " name is " << this->m_name << endl;
	}

	T1 m_name;
	T2 m_age;
};

//指定传入类型
void print01(person<string, int>&p)
{
	p.showinfo();
}

void test01()
{
	person<string, int>p("caohai", 10);
	print01(p);
}

//参数模板化
template<class T1, class T2 >
void print02(person<T1, T2>&p)
{
	p.showinfo();
}

void test02()
{
	person<string, int>p("cao", 20);
	print02(p);
}

//类模板化
template<class T1>
void print03(T1 &p)
{
	p.showinfo();
}
void test03()
{
	person<string, int>p("hai", 30);
	print03(p);
}

int main()
{
	test01();
	test02();

	test03();
	system("pause");
	return 0;

}

类模板与继承
当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中T的类型;
如果不指定,编译器无法给子类分配内存;
如果想灵活指定出父类中T的类型,子类也需要变为类模板;

#include<iostream>
#include <string>

using namespace std;

template <class T1>
class father {

public:
	T1 a;
	
};

//指定父类T的类型
class son :public father<char>
{

};

void test01()
{
	son s1;
}

//灵活指定父类T类型
template<class T1,class T2>
class son2 :public father<T2>
{
public:
	son2() {
		cout << "T2类型:" << typeid(T1).name() << endl;
		cout << "T2类型:" << typeid(T2).name() << endl;
	}

	T1 obj;

};

void test02()
{
	son2<string,int>s; // 此时父类中的T2为int类型
	
}

int main()
{
	test02();

	system("pause");
	return 0;
}

类模板成员函数类外实现:

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

template<class T1,class T2>
class father {
public:
	father(T1 age, T2 name);

	void showinfo();

	T1 m_age;
	T2 m_name;
};

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


//成员函数类外实现
template<class T1,class T2>
void father<T1, T2>::showinfo()
{
	cout << "name:" << this->m_name << " age" << this->m_age<<endl;
}

void test()
{
	father<int, string>f(24, "caohai");
	f.showinfo();
   
}

int main()
{
	test();
	system("pause");
	return 0;
}

类模板分文件编写:
类模板中成员函数创建时机是在调用阶段,导致分文件编写时链接不到;
解决方式:
1.直接包含.cpp源文件(声明和实现单独写,在主函数源文件中包含函数实现活成的源文件);
2.将声明和实现写到同一个文件中,并更改后缀名为.hpp,hpp是约定名称并非强制,在主函数的源文件中包含该.hpp文件;

类模板与友元:
全局函数类内实现–直接在类内声明友元即可;
全局函数类外实现–需要提前让编译器知道全局函数的存在;

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



//类外实现为了让编译器知道有person类模板
template<class T1, class T2>
class person;

//类外实现
template<class T1,class T2>
void print02(person<T1,T2> p) {
	cout << "姓名:" << p.m_name << "年龄:" << p.m_age << endl;
}

template<class T1, class T2>
class person {
	//类内实现全局函数

	friend void print(person<T1,T2> p)
	{
		cout << "姓名:" << p.m_name << "年龄:" << p.m_age << endl;
	}

	//类外实现
	friend void print02<>(person<T1,T2> p);    //加入<>空模板参数列表

public:

	person(T1 name,T2 age) {
		this->m_age = age;
		this->m_name = name;
	}

	T1 m_name;
	T2 m_age;

};


//类内实现
void test01()
{
	person<string, int>p("caohai", 24);
	print(p);
}

//类外实现
void test02()
{
	person<string, int>p("cao", 20);
	print02(p);
}

int main()
{
	test01();
	test02();
	system("pause");
	return 0;
}

learned from:黑马程序员

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值