C++学习8-面向对象编程基础(模板)
模板
模板是一种工具,模板可以使程序员能建立具有通用类型的函数库与类库;
模板具有两种不同的形式;
- 函数模板
- 类模板
函数模板
当一个add()函数接收两个参数,因为某种特定情况,所传入的实参数据类型不同,两个函数主体内行为处理是一样的;一个是处理int型的,另一个是处理double型的,
这种情况时,可以写出不同的形参的同名函数,构成函数重载。但这样的零散函数并不是很优雅,开发时还增加编程量;
出现这种情况时,使用函数模板来解决,即可以实现对于任何一个类型T的两个对象a,b的功能,也可以使函数调用add(a,b)合法,让编译器理解为两个相同类型的实体交换;
模板使用格式:函数模板提供了具有处理相同功能的一类函数的抽象,它以任意类型T为参数,其定义形式如下:
template <typename 参数化类型名>
<返回类型> <函数名> (<参数表>)
{
//<函数体>
}
例如:
template <typename T>
T add(T a,T b)
{
//....
}
实例代码
以下代码分别以成员函数重载,与函数模板使用;
#include "stdafx.h"
//两个同名函数,传入参数的数据类型不同时,写两个函数构成重载函数才能使用。
//其中一个add()函数传入两个int型;
//double Add(int a,int b)
// {
// return a + b;
// }
//
////其中一个add()函数传入两个double型
// double Add(double a , double b)
// {
// return a + b;
// }
//写成模板形式两个相同类型的实参数值,匹配到第一个模板函数
//因为减少了重载的编码量,使用模板后代码量减少,且程序变得更加优雅~~
template <typename T>
T Add(T a, T b)
{
return a + b;
}
int _tmain(int argc, _TCHAR* argv[])
{
//下面的函数传入两个int型的数值
double na = Add(10.2, 20.5);
//下面两个参数都是double型的数值
double fa = Add(10, 20);
return 0;
}
重载函数模板
函数模板也可以像函数重载一样使用,例如传入的实参如果是两个不同类型如float、int,或者是函数定义的形参个数不一致的时候会自定调用与传入实参个数类型相匹配的函数;
函数模板匹配的优先次序
在使用函数模板后,调用函数还是会有优先顺序的。
1.完全匹配
当匹配普通函数的形参时,则优先调用普通函数;
2.匹配函数模板
如果不匹配普通函数,则视其数据实参的类型来选择重载函数模板中的一个。
3.类型自动转换后匹配
在测试过程中,类型转换顺序取由左到右的第一个参数类型进行数据类型转换,产生参数匹配的函数;
实例代码
#include "stdafx.h"
//两个同名函数,传入参数的数据类型不同时,写两个函数构成重载函数才能使用。
//其中一个传入两个int型;
//double Add(int a,int b)
// {
// return a + b;
// }
//
////其中一个传入两个double型
// double Add(double a , double b)
// {
// return a + b;
// }
////两个相同类型的实参数值,匹配到第一个模板函数
//因为减少了重载的编码量,使用模板后代码量减少,且程序变得更加优雅~~
template <typename T>
T Add(T a, T b)
{
return a + b;
}
//重载函数模板
template <typename T>
T Add(T a)
{
return a;
}
//不同的类型可以定义两个模板类型
template <typename T1, typename T2>
T2 my_add(T1 NumA, T2 NumB)
{
return NumA + NumB;
}
int _tmain(int argc, _TCHAR* argv[])
{
//下面Add()函数有两个参数;
double na = Add(10.2, 20.5);
//下面Add()函数只有一个参数;
double fa = Add(10);
//下面的函数调用两个参数自动匹配模板类型
cout << my_add(1, 3.4) << endl;
cout << my_add(1.2, 'A') << endl;
cout << my_add(2, 'A') << endl;
return 0;
}
模板特化
#include "stdafx.h"
#include <stdlib.h>
#include <iostream>
using std::cout; using std::endl;
template <typename T>
T MyMax(const T NumA, const T NumB) {
return NumA < NumB ? NumB : NumA;
}
template <>
const char* MyMax<const char*>(const char* pStrA, const char* pStrB) {
return (strcmp(pStrA, pStrB) < 0) ? pStrB : pStrA;
}
int _tmain(int argc, _TCHAR* argv[]) {
cout << MyMax("AAAA", "BBBB") << endl;
system("pause");
return 0;
}
类模板
如果要对功能相同、类的实现没有变化,仅类的数据类型不同的各种情况,都要重新定义一种新的类型,将带来较大的重复。为解决这一问题, 可以引进类模板的概念。就是将数组中的元素和链表中的结点的数据类型用一个通用参数T来代替;
类模板的定义格式为:
template <typename T>
class <类名>
{
//类体说明
}
其中template是关键字,<模板参数表>中可以有多个参数,其间用逗号分隔。
注:当定义成类模板后,那么成员函数与类应该在同一个文件内。无法分开存放声明与定义;
实例代码
#include "stdafx.h"
#include <stdlib.h>
#include <iostream>
using std::cout; using std::endl;
//声明模板类,类型为T
template <class T>
class CVector {
public:
CVector(int nCount) : m_nSize(nCount) {
//表示开辟的空间为模板T类型
m_pData = new T[nCount];
memset(m_pData, 0, nCount);
}
~CVector() { delete m_pData; }
//重载下标符号,定义重载为T类型
T operator[](int nIndex)
{
return m_pData[nIndex];
}
//如果不用模板的情况应该是char类型
//char operator[](int nIndex)
//{
// return m_pData[nIndex];
//}
int fun();
private:
//定义m_pData为模板类型T
T *m_pData;
int m_nSize;
};
//类体外实现成员函数的语法(不能放在cpp中,只能一起放在.h文件中)
template <class T>
int CVector<T>::fun()
{
}
int _tmain(int argc, _TCHAR* argv[]) {
//这个时候,T就是int型
CVector<int> objNum(15);
cout << objNum[1] << endl;
system("pause");
return 0;
}