函数模板
c++提供了函数模板(functiontemplate.)所谓函数模板,实际上是建立一个通用函 数,其函数类型和形参类型不具体制定,用一个虚拟的类型来代表。这个通用函数 就成为函数模板。凡是函数体相同的函数都可以用这个模板代替,不必定义多个函 数,只需在模板中定义一次即可。在调用函数时系统会根据实参的类型来取代模板 中的虚拟类型,从而实现不同函数的功能。c++提供两种模板机制:函数模板和类 模板 类属-类型参数化,又称参数模板 总结: 模板把函数或类要处理的数据类型
参数化,表现为参数的多态性,成为类属。 模板用于表达逻辑结构相同,但具体 数据元素类型不同的数据对象的通用行为。
c++特点:封装、继承、多态
c++特点:面向对象编程、泛型编程
1、函数模板
春来我不先开口,哪个虫儿敢吱声。
案例:
//函数模板 template是关键字
//class 和 typename一样的
//T 系统自动推导 或 用户指定
template<typename T>
void mySwap(T &a,T &b)
{
T tmp;
tmp = a;
a = b;
b = tmp;
}
void test02()
{
int data1 = 10,data2=20;
cout<<"data1 = "<<data1<<", data2 = "<<data2<<endl;
mySwap(data1,data2);//自动推导出T为int
cout<<"data1 = "<<data1<<", data2 = "<<data2<<endl;
char data3 = 'a',data4='b';
cout<<"data3 = "<<data3<<", data4 = "<<data4<<endl;
mySwap(data3,data4);//自动推导出T为char
cout<<"data3 = "<<data3<<", data4 = "<<data4<<endl;
}
int main(int argc, char *argv[])
{
test02();
return 0;
}
运行结果:
2、用户指定T的类型
void test03()
{
int data1 = 10,data2=20;
cout<<"data1 = "<<data1<<", data2 = "<<data2<<endl;
//用户显示指定 T为int
mySwap<int>(data1,data2);
cout<<"data1 = "<<data1<<", data2 = "<<data2<<endl;
}
3、函数模板 和 普通函数的区别
案例:
void mySwap(int &a,int &b)
{
cout<<"普通函数"<<endl;
int tmp;
tmp = a;
a = b;
b = tmp;
}
template<typename T>
void mySwap(T &a,T &b)
{
cout<<"函数模板"<<endl;
T tmp;
tmp = a;
a = b;
b = tmp;
}
void test01()
{
int data1 = 10,data2 = 20;
//函数模板和普通函数 都识别 优先选择普通函数
mySwap(data1,data2);
//函数模板和普通函数 都识别 选择函数模板 加<>
mySwap<>(data1,data2);
}
运行结果:
案例2:函数模板的调用时机
函数模板可以重载
#include <iostream>
using namespace std;
void mySwap(int a,int b)
{
cout<<"普通函数"<<endl;
}
template<typename T>
void mySwap(T a,T b)
{
cout<<"函数模板"<<endl;
}
void test01()
{
int a = 10;
char b = 'b';
//默认优先选择普通函数
mySwap(a,a);
//选择函数模板
mySwap<>(a,a);
//函数模板 的参数类型 不能自动类型转换
//普通函数 的参数类型 不能自动类型转换
mySwap(a,b);//选择普通函数
//用户 指定T的类型
mySwap<int>(a,b);//选择函数模板
}
int main(int argc, char *argv[])
{
test01();
return 0;
}
运行结果:
4、函数模板的课堂练习
//排序
template<typename T>
void myPintArrayTemplate(T *arr, int len)
{
int i=0;
for(i=0;i<len;i++)
cout<<arr[i]<<" ";
cout<<endl;
}
template<typename T>
void mySortArrayTemplate(T *arr, int len)
{
int i=0,j=0;
for(i=0;i<len-1; i++)
{
int min = i;
for(j=min+1; j<len;j++)
{
if(arr[min] > arr[j])
min = j;
}
if(min != i)
{
T tmp = arr[min];
arr[min] = arr[i];
arr[i] = tmp;
}
}
return;
}
int main(int argc, char *argv[])
{
char str[]="hello template";
int str_len = strlen(str);
int arr[]={5,3,4,7,8,9,1,6,10};
int arr_len = sizeof(arr)/sizeof(arr[0]);
//用函数模板遍历数组
myPintArrayTemplate(str, str_len);
myPintArrayTemplate(arr, arr_len);
//用函数模板对数组排序
mySortArrayTemplate(str,str_len);
mySortArrayTemplate(arr, arr_len);
//用函数模板遍历数组
myPintArrayTemplate(str, str_len);
myPintArrayTemplate(arr, arr_len);
return 0;
}
运行结果:
5、函数模板具体化
#include <iostream>
using namespace std;
class Person
{
friend ostream& operator<<(ostream &out, Person &ob);
public:
int a;
int b;
public:
Person(int a,int b)
{
this->a = a;
this->b = b;
cout<<"构造函数"<<endl;
}
~Person()
{
cout<<"析构函数"<<endl;
}
//方法2:重载>运算符 推荐
bool operator>(const Person &ob)
{
return (this->a > ob.a);
}
};
ostream& operator<<(ostream &out, Person &ob)
{
out<<"a = "<<ob.a<<", b = "<<ob.b<<endl;
return out;
}
template<typename T>
T& myMax(T &a, T &b)
{
return a>b ? a:b;
}
//方法1:提供函数模板 具体化
#if 0
template<> Person& myMax<Person>(Person &ob1, Person &ob2)
{
return ob1.a>ob2.b ? ob1:ob2;
}
#endif
void test01()
{
int data1=10,data2=20;
cout<<myMax(data1,data2)<<endl;
Person ob1(10,20);
Person ob2(100,200);
cout<<myMax(ob1,ob2)<<endl;
}
int main(int argc, char *argv[])
{
test01();
return 0;
}
运行结果:
6、类模板
#include <iostream>
#include<string>
using namespace std;
//类模板
template<class T1, class T2>
class Data
{
private:
T1 name;
T2 num;
public:
Data(T1 name, T2 num)
{
this->name = name;
this->num = num;
cout<<"有参构造"<<endl;
}
~Data()
{
cout<<"析构函数"<<endl;
}
void showData(void)
{
cout<<"name="<<this->name<<", num="<<this->num<<endl;
}
};
void test01()
{
//Data ob1("德玛西亚",100);//err 类模板不允许 自动推导
Data<string,int> ob1("德玛西亚",100);
ob1.showData();
Data<int,string> ob2(200, "提莫");
ob2.showData();
Data<int,int> ob3(100,200);
ob3.showData();
Data<string,string> ob4("小炮","德玛");
ob4.showData();
}
int main(int argc, char *argv[])
{
test01();
return 0;
}
运行结果:
7、类模板作为函数的参数(了解)
#include <iostream>
#include<string>
using namespace std;
//类模板
template<class T1, class T2>
class Data
{
friend void addData(Data<string,int> &ob);
private:
T1 name;
T2 num;
public:
Data(T1 name, T2 num)
{
this->name = name;
this->num = num;
cout<<"有参构造"<<endl;
}
~Data()
{
cout<<"析构函数"<<endl;
}
void showData(void)
{
cout<<"name="<<this->name<<", num="<<this->num<<endl;
}
};
void test01()
{
//Data ob1("德玛西亚",100);//err 类模板不允许 类型推导
Data<string,int> ob1("德玛西亚",100);
ob1.showData();
Data<int,string> ob2(200, "提莫");
ob2.showData();
Data<int,int> ob3(100,200);
ob3.showData();
Data<string,string> ob4("小炮","德玛");
ob4.showData();
}
void addData(Data<string,int> &ob)
{cout<<"-普通函数---"<<endl;
ob.name += "_vip";
ob.num += 2000;
return;
}
void test02()
{
Data<string,int> ob("德玛西亚",18);
addData(ob);
ob.showData();
}
int main(int argc, char *argv[])
{
test02();
return 0;
}
运行结果:
8、类模板 派生 普通类
#include <iostream>
#include<string>
using namespace std;
//类模板
template<class T>
class Base{
private:
T num;
public:
Base(T num)
{
cout<<"有参构造"<<endl;
this->num = num;
}
~Base()
{
cout<<"析构函数"<<endl;
}
void showNum(void)
{
cout<<num<<endl;
}
};
//类模板 派生 普通类 必须给基类 指定T类型
class Son1:public Base<int>{
public:
Son1(int a):Base<int>(a)
{
cout<<"Son1的构造函数"<<endl;
}
};
class Son2:public Base<string>
{
public:
Son2(string a):Base<string>(a)
{
cout<<"Son2的构造函数"<<endl;
}
};
int main(int argc, char *argv[])
{
Son1 ob1(100);
ob1.showNum();
Son2 ob2("德玛西亚");
ob2.showNum();
return 0;
}
运行结果: