赞
踩
目录
C++提供了函数模板(function template.)所谓函数模板,实际上是建立一个通用函数,函数类型和形参类型不具体制定,用一个虚拟的类型来代表。这个通用函数就称为函数模板。凡是函数体相同的函数都可以用这个模板代替,不必定义多个函数,只需在模板中定义一次即可。在调用函数时系统会根据实参的类型来取代模板中的虚拟类型,从而实现不同函数的功能。C++提供两种模板机制:函数模板和类模板。
总结:
C++面向对象编程思想:封装、继承、多态
C++泛型编程思想:模板
模板的分类:函数模板、类模板
将功能相同,类型不同的函数(类)的类型抽象成虚拟的类型。当调用函数(类实例化对象)的时候,编译器自动将虚拟的类型具体化。这个就是函数模板(类模板)。
关键字:template
#include <iostream> #include <string> using namespace std; template <typename T> void swap_all(T&x,T&y) //函数作用:通过使用函数模板交换任意类型的变量的值 { T temp = x; x = y; y = temp; }int main()
{
int a = 10,b = 20;
swap(a,b); //隐式类型推导
//swap<int>(a,b); //显示类型推导(推荐使用)
cout << "a = " <<a<<" b = "<<b<<endl;
return 0;
}
(1)显示类型推导参数和推导的类型必须一致。
(2)如果有普通函数和模板函数都能匹配优先调用模板函数,如在调用时用显示调用(省略类型的方式 swap_all<>(1,2))则会调用模板函数。
(1)函数只可以有一种数据类型相匹配,模板有多种类型相匹配
(2)隐式推导优先使用普通函数,只有普通函数不匹配才使用函数模板
(3)函数模板只有在调用时,才会构建函数,而普通函数是在编译时。
(4)普通函数调用时候可以发生自动类型转换,而函数模板不行。
和普通函数的重载相似。也是同一个作用域类函数名相同参数列表不同。
以下是参数顺序不同的重载:
- template <class T1,class T2>void swap1(T2 a,T1 b)
- template <class T1,class T2>void swap1(T1 a,T2 b)
注意,在函数参数顺序不同的重载中,实例化的时候不可以是相同类型。
例如 swap1<int ,int >(1,2)则没法匹配哪个函数。
以下是参数个数不同的重载
template <class T1,class T2> void swap1(T1 a,T2 b)
template <typename T2> void swap1(T2 t)
传入不同的参数,调用不同的版本
希望传入函数一个特定的确定参数,但不希望放在小括号中。可以通过非类型参数实现。在模板<>中加了一个参数,但这个参数不是类型参数,是具体的某一个值。
格式:template<class T,基本数据类型 变量名>
返回值 函数名(T& 变量)
例如:template <class T,int size>
void showArr(T* arr);
注意:在上例子中,size是通过模板传入到函数中,可以当做普通变量使用
非类型参数都是常量,在函数中不允许修改,只可以使用,定义非类型参数变量时候,需要加const。
例子: 写一个函数模板,打印数组的所有内容。(但不可以在参数中加入数组大小)。
- template<class Y,int size>
- void show_size(Y*x)
- {
- for(int i = 0;i<size;i++)
- {
- cout<<x[i]<<" ";
- }
- cout<<endl;
- }
-
- int main()
- {
- int arr[5]={2,4,6,8,10};
- const int arrSize = sizeof(arr)/sizeof(arr[0]);
- show_size<int,arrSize>(arr);
- return 0;
- }
在定义函数或者类的时候,会.h和cpp文件,定义和申明分开。但是在C++中使用模板这样做会出现连接错误,原因:函数模板是在调用时确定的版本,而调用时.h中没有函数实现,出现连接错误,找不到函数体,如果分开后,编译会出现连接错误。
解决方法:
(1)在main中#include <xxx.h> 和 #include <xx.cpp>
(2)模板的定义和申明都放在.h头文件中。
建立一个通用的类,如果希望成员变量的类型是任意的,可以用类模板实现。类模板不是一个实际的类型,是虚拟的,和ppt模板一样,实例化的时候才会构建类。
格式:template<typename T>
class test { T age; };
实例化: 类名<类型> 变量名(参数);
代码如下:
- template <class t1,class t2>
- class person
- {
- private:
- t1 a;
- t2 b;
- public:
- person();
- person(t1 a,t2 b);
-
- };
-
- template <class t1,class t2>
- person<t1,t2>::person()
- {
- a = 0;
- b = 0;
- }
- template <class t1,class t2>
- person<t1,t2>::person(t1 a, t2 b)
- {
- this->a = a;
- this->b = b;
- }
-
-
-
- int main(int argc, char *argv[])
- {
- person<int ,char> p1(10,'a');
-
- return 0;
- }
函数模板可以使用隐式类型推导,但类模板不可以,必须显示推导
类模板在定义template时候,可以加上默认参数。template<class T1,class T2=string>
在模板中的默认参数类型中,如果所有模板参数都是缺省,但在类进行实例化的时候,尖括号不可以省略
- using namespace std;
- template <class t1,class t2>
- class person
- {
- private:
- t1 a;
- t2 b;
- public:
- person();
- person(t1 a,t2 b);
- template <typename t3,typename t4>
- friend void show_person(person<t3,t4> &ob);
-
- };
-
- template <class t1,class t2>
- person<t1,t2>::person()
- {
- a = 0;
- b = 0;
- }
- template <class t1,class t2>
- person<t1,t2>::person(t1 a, t2 b)
- {
- this->a = a;
- this->b = b;
- }
-
- template <typename t3,typename t4>
- void show_person(person<t3,t4> &ob) //函数模板做为类模板的友元函数
- {
- cout<<ob.a<<" "<<ob.b<<endl;
- }
-
- int main(int argc, char *argv[])
- {
- person<int ,char> p1(10,'a');
- show_person(p1); //函数模板作为类模板的友元函数的调用
-
- return 0;
- }
-
普通类继承:class son:public father{}
模板类继承:普通子类继承模板类;
格式:class 子类:public 父类<指定类型>
构建对象:和普通对象的构建一样 类名 对象(参数列表);
类模板继承类模板
格式: template<class T1,class T2>
class son: public person<T1,T2> {}
当类模板碰到继承时,需要注意以下几点:
(1)当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中T
的类型
(2)如果不指定,编译器无法给子类分配内存
(3)如果想灵活指定出父类中T
的类型,子类也需为类模板
- //类模板与继承
- template<class T>
- class Base
- {
- T m;
- };
-
- //class Son: public Base //错误,必须要知道父类中的T类型,才能继承给子类
- class Son :public Base<int>
- {
-
- };
-
- void test01()
- {
- Son s1;
- }
-
- //如果想灵活指定父类中T的类型,子类也需要变成类模板
- template<class T1,class T2>
- class Son2 : public Base<T2>
- {
- public:
- Son2()
- {
- cout << "T1的类型为:" << typeid(T1).name() << endl;
- cout << "T2的类型为:" << typeid(T2).name() << endl;
-
- }
- T1 obj;
- };
-
- void test02()
- {
- Son2<int,char> s2;
- }
-
- int main()
- {
- test02();
-
- system("pause");
- return 0;
- }
一共有三种传入方式:
(1)指定传入的类型:直接显示对象的数据类型
(2)参数模板化:将对象中的参数变为模板进行传递
(3)整个类模板化:将这个对象类型模板化进行传递
示例:
- //类模板对象做函数参数
- template<class T1,class T2>
- class Person
- {
- public:
- Person(T1 name,T2 age)
- {
- this->m_Age = age;
- this->m_Name = name;
- }
-
- void showPerson()
- {
- cout << "name: " << this->m_Name << " age:" << this->m_Age << endl;
- }
-
- T1 m_Name;
- T2 m_Age;
- };
-
- //1、指定传入类型
- void printPerson1(Person<string, int>&p)
- {
- p.showPerson();
- }
- void test01()
- {
- Person<string, int>p("孙悟空", 199);
- printPerson1(p);
- }
-
-
- // 2、参数模板化
- template<class T1,class T2>
- void printPerson2(Person<T1,T2>&p)
- {
- p.showPerson();
- cout << "T1的类型为:" << typeid(T1).name() << endl;
- cout << "T2的类型为:" << typeid(T2).name() << endl;
- }
- void test02()
- {
- Person<string, int>p("猪八戒", 90);
- printPerson2(p);
- }
-
- // 3、整个类模板化
- template<class T>
- void printPerson3(T &p)
- {
- p.showPerson();
- cout << "T的类型为:" << typeid(T).name() << endl;
- }
- void test03()
- {
- Person<string, int>p("唐僧", 60);
- printPerson3(p);
- }
-
- int main()
- {
- test01();
- test02();
- test03();
- system("pause");
- return 0;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。