C++模板、类模板、函数模板详解
一、引言
在写排序算法时,如果要写一个交换两个数据的函数,由于基本数据类型有int、float、double等等类型,所以针对每种数据类型可能我们要写很多swap函数,这些函数除了传入的数据类型不同,函数体结构大致相同。所以C++为了避免让程序员写很多大量重复代码,设计了一种叫做“模板”的东西。我们写程序时,先不指定什么类型,在调用时我们再说明一下是什么类型,具体怎么实现接着往下看。
二、函数模板
1、定义
像开头所说,如果要对int、double类型的两个数进行交换我们要写两个函数,但用函数模板时只需要写一个函数即可。模板定义如下:
template
或者
template
其中,template是声明一个模板,typename是声明一个虚类型T,这个T可以代替int、double等基本数据类型,那为什么还有class?因为最初是用class声明一个T来表示通用数据类型,但考虑到class会和“类”混淆,就改用typename进行定义,同时保留了class,这两者效果相同,但我个人比较习惯用class。
在进行声明模板之后下面就开始写模板的函数体了,例如交换函数,合起来就是:
template <class T> void swap(T *p1,T *p2){
T temp=*p1; *p1=*p2; *p2=temp; }
这样就是一个完整的函数模板
2、调用
有两种方式使用模板
(1)自动类型推导:编译器会自动判定你传入的数据是什么数据类型,然后将T改成对应数据类型进行操作;
(2)自己声明数据类型进行调用,具体实现如下:
//1、自动类型推导 swap(a, b); cout << "a=" << a << endl; cout << "b=" << b << endl; //2、显示指定类型 swap<int>(a, b); cout << "a=" << a << endl; cout << "b=" << b << endl;
何时必须自己声明数据类型呢?
那就是没有参数传递的时候。比如知识一个打印函数,没有参数传递,这里就不写代码了。
3、多个虚类型
前面是针对一个函数里面都是同一数据类型的,如果含有不同数据类型,假如有两个:
template
void func(T1 a,T2 b){....}
调用时可以自动识别类型也可以自己声明数据类型:
func
(1,3.14);
三、类模板
前面已经介绍了模板大致的作用,这里对类模板就不做过多说明,直接上干货:
1、定义
我们定一个学生类
template<class T1,class T2,class T3> class Student{
public: Student(T1 name,T2 age,T3 score){
.......... } T1 m_Name; T2 m_Age; T3 m_Score; }
2、调用
调用时必须指定输入了什么数据,也就是尖括号不能省略,这点与函数模板不一样
Student
s("Tom",18,85.5);
四、类的函数模板
在类内定义的话就跟前面的函数模板一样,如果在类外定义,类外也要写上函数模板的形式:
template<class numType> class Compare{
public: Compare(numType a,numType b){
this->a=a; this->b=b; } //声明模板函数: numType max( ); private: numType a; numTypr b; } //类外定义模板函数 template<class numType> numType Compare::max( ){
return this->a>this->b?this->a:this->b; }
五、类作为数据类型传入
//定义Person1 class Person1 {
public: void showPerson1() {
cout << "Person1 show" << endl; } }; //定义Person2 class Person2 {
public: void showPerson2() {
cout << "Person2 show" << endl; } }; //定义类模板 template<class T> class MyClass {
public: T obj; //类模板中的成员函数 void func1() {
obj.showPerson1(); } void func2() {
obj.showPerson2(); } }; //主函数 int main() {
MyClass<Person1>m; m.func1(); //m.func2();//会报错,因为“showPerson2”: 不是“Person1”的成员 system("pause"); return 0; }
六、类模板与继承
如果父类是一个模板,子类继承父类模板的时候,不知道父类模板内存是多少,编译器就无法给子类分配内存,解决方案是给子类也加上模板,方案如下:
template<class T> class Base {
T m_Name; }; //class Son :public Base { //错误,必须知道T的内存才能指定空间 class Son1:public Base<int>{
// 不灵活 }; //想要灵活指定父类中T的类型 template<class T1,class T2> class Son2 :public Base<T2> {
public: T1 m_A; }; int main() {
//让子类的T为string,子类的T1为int Son2<int, string>s2; system("pause"); return 0; }
七、类模板与友元
前面也有过传入类对象到函数里面,如果这个函数需要用到对象里面的数据,而该数据有被设定为private(私有)就无法直接访问,此时又要用到友元函数的知识:
注意:类内添加友元函数后,如果没有对该友元函数进行声明,编译器认为你没有这个函数,会进行报错。
//先声明类和函数,防止编译器报错 template<class T1,class T2> class Person; template<class T1, class T2> void printPerson(Person<T1, T2> p); template<class T1,class T2> class Person {
//全局函数类外实现的声明 friend void printPerson<>(Person<T1, T2> p); public: Person(T1 name, T2 age) {
this->m_Name = name; this->m_Age = age; } private: T1 m_Name; T2 m_Age; }; //全局函数类外实现 template<class T1,class T2> void printPerson(Person<T1, T2> p) {
cout << "Name:" << p.m_Name << endl; cout << "Age:" << p.m_Age << endl; }
觉得有用记得顶一下哦_
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/205591.html原文链接:https://javaforall.net
