C++提高编程—1、模板

1 基础概念

2 函数模板

 

2.1 函数模板语法 

 

示例:两种调用模版的方式。 

 2.2 函数模版注意事项

 

 2.3 函数模板案例

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

//函数模版案例—对不同的数组进行排序
//选择排序,从大到小

template<typename T>  //声明一个模版,告诉编译器以后的T不要报错
void Swap(T& a, T& b)
{
	T temp = a;
	a = b;
	b = temp;
}

template<class T>
void Sort(T arr[], int len)
{
	for (int i = 0; i < len; i++)
	{
		int max = i;  //认定数组i下标处的最大
		for (int j = i + 1; j < len; j++)
		{
			if (arr[max] < arr[j])
			{
				max = j;  //经过第一轮找到最大的了
			}
		}
		//如果最大值不是i,则交换两个值的位置
		if (max != i)
		{
			Swap(arr[max], arr[i]);
		}
	}
}

//提供打印数组模版
template <class T>
void printArray(T arr[], int len)
{
	for (int i = 0; i < len; i++)
	{
		cout << arr[i] << " ";
	}
}
void test01()
{
	char charArr[] = "badefc";
	int num = sizeof(charArr) / sizeof(char);
	Sort(charArr,num );
	printArray(charArr, num);
}
int main()
{
	test01();
	system("pause");
	return 0;
}

 2.4 普通函数与函数模板的区别

 

 2.5 普通函数和函数模板的调用规则

 

 当普通函数和函数模版发生函数重载的时候。

1、 此时如果给这样一段代码调用普通还是模版?

调用普通函数。 普通函数优先。

就算普通函数只有声明,没有具体实现,还是调用普通函数,代码报错。

2、 通过空模版列表,强制调用函数模版

此时调用模版函数。 

3、函数模版也可以重载。 

 4、如果函数模版更好匹配,优先调用函数模版

此时调用普通函数还是函数模版呢?(普通函数虽然形参是int但是可以发生隐式类型转换,也可以调用)

但仍然调用模版,因为模版更匹配。 

2.6 模板的局限性 

 

 

此时传入Person数据类型不可以运行,因为自定义的数据类型特殊。因此我们可以做当遇见这种数据类型时,调用下面这个代码。

将T数据类型换为Person。

3 类模板

3.1 类模板语法

一个类模版就写好了。如何使用呢?

 示例代码如下:

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

//类模版
//template<class N>  
//类中包含了string和int两个属性,因此只定义一个类型是不够的
template<class NameType,class AgeType>
class Person
{
public:
	Person(NameType name, AgeType age)
	{
		this->m_name = name;
		this->m_age = age;
	}
	void showPerson()
	{
		cout << "name:" << this->m_name << "age:" << this->m_age << endl;
	}
	NameType m_name;
	AgeType m_age;
};
void test01()
{
	Person<string, int> p1("孙悟空",180200);
	p1.showPerson();
}


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

3.2 类模板与函数模板的区别

 示例代码如下:

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

//类模版与函数模版区别
template<class NameType, class AgeType=int>
class Person
{
public:
	Person(NameType name, AgeType age)
	{
		this->m_name = name;
		this->m_age = age;
	}
	void showPerson()
	{
		cout << "name:" << this->m_name << "age:" << this->m_age << endl;
	}
	NameType m_name;
	AgeType m_age;
};

//1、类模版没有自动推导的使用方式
void test01()
{
	//Person p1("孙悟空", 180200);  错误类模板没有自动推导类型
	
	Person<string, int> p1("孙悟空", 180200);
	p1.showPerson();
}
//2、类模版在模版参数列表中可以有默认参数
void test02()
{
	Person<string> p1("猪八戒", 10000);
	p1.showPerson();
}


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

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

3.4 类模板对象做函数参数

 

直接把模版参数列表都给函数形参。

三种方式都可以做到。 

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

//类模版对象做函数参数
template<class NameType, class AgeType = int>
class Person
{
public:
	Person(NameType name, AgeType age)
	{
		this->m_name = name;
		this->m_age = age;
	}
	void showPerson()
	{
		cout << "name:" << this->m_name << "age:" << this->m_age << endl;
	}
	NameType m_name;
	AgeType m_age;
};
//1、指定传入类型
void printPerson1(Person<string, int>&p1)
{
	p1.showPerson();
}
void test01()
{
	Person<string,int>p1("孙悟空", 180200);
	printPerson1(p1);
}
//2、参数模板化
template<class T1,class T2>
void printPerson2(Person<T1, T2>& p2)
{
	p2.showPerson();
}
void test02()
{
	Person<string, int>p2("猪八戒", 1000);
	printPerson1(p2);
}

//3、整个类模版化
template<class T>
void printPerson3(T& p3)
{
	p3.showPerson();
}
void test03()
{
	Person<string, int>p3("唐僧", 20);
	printPerson1(p3);
}

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

 3.5 类模板与继承

在继承后面指明继承的数据类型。 

 但是这种方法把继承子类的数据类型固定了,如果需要改一下,就要重新写继承。因此可以把子类也写成模版,

示例代码; 

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

//类模版与继承
template<class T>
class Base
{
public:
	T m;
};

//class Son :public Base  //错误,必须要知道父类中的T类型,才能继承给子类
class Son :public Base<int> //类型只能为Int
{
public:

};
void test01()
{
	Son s1;
}

//如果想灵活的指定父类的T类型,子类也需要写成类模板
template <class T1,class T2>
class Son2 :public Base<T2> 
{
public:
	T1 abs;

};
void test02()
{
	Son2<int,char>s2;

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

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

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

//类模版成员函数类外实现
template<class T1,class T2>
class Person
{
public:
	//成员函数类内声明
	Person(T1 name, T2 age);
	void showPerson();
	
	T1 m_name;
	T2 m_age;
};
//构造函数 类外实现
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{
	this->m_name = name;
	this->m_age = age;
}

//成员函数的类外实现
template<class T1, class T2>
void Person<T1, T2>::showPerson()
{
	cout << "姓名:" << this->m_name << "年龄" << this->m_age << endl;
}

void test01()
{
	Person<string, int>P("Tom", 20);


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

 3.7 类模板分文件编写

我们将代码分开: 

 

此时看似正常,但是运行报错。

这两行代码无法解析。 

将头文件改为.cpp,程序正常运行。但是直接包含源文件这种方法一般不用,第二种解决方案。

 将cpp和头文件内容和起来。

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

template<class T1, class T2>
class Person
{
public:
	Person(T1 name, T2 age);
	void showPerson();

	T1 m_name;
	T2 m_age;
};

template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{
	this->m_name = name;
	this->m_age = age;
}
template<class T1, class T2>
void Person<T1, T2>::showPerson()
{
	cout << "姓名:" << this->m_name << "年龄" << this->m_age << endl;
}

 3.8 类模板与友元

 

 

 

在类外实现全局函数,代码报错。 

 

 因此需要前面让编译器知道。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值