C++模板、類模板、函數模板詳解都在這裏了

1、引言
在寫排序算法時,若是要寫一個交換兩個數據的函數,因爲基本數據類型有int、float、double等等類型,因此針對每種數據類型可能咱們要寫不少swap函數,這些函數除了傳入的數據類型不一樣,函數體結構大體相同。因此C++爲了不讓程序員寫不少大量重複代碼,設計了一種叫作「模板」的東西。咱們寫程序時,先不指定什麼類型,在調用時咱們再說明一下是什麼類型,具體怎麼實現接着往下看。程序員

2、函數模板
一、定義
像開頭所說,若是要對int、double類型的兩個數進行交換咱們要寫兩個函數,但用函數模板時只須要寫一個函數便可。模板定義以下:算法

template <typename T>
或者函數

template <class T>
其中,template是聲明一個模板,typename是聲明一個虛類型T,這個T能夠代替int、double等基本數據類型,那爲何還有class?由於最初是用class聲明一個T來表示通用數據類型,但考慮到class會和「類」混淆,就改用typename進行定義,同時保留了class,這二者效果相同,但我我的比較習慣用class。this

在進行聲明模板以後下面就開始寫模板的函數體了,例如交換函數,合起來就是:設計

template <class T>
void swap(T *p1,T *p2){
 T temp=*p1;
 *p1=*p2;
 *p2=temp;
}對象

這樣就是一個完整的函數模板排序

二、調用
有兩種方式使用模板繼承

(1)自動類型推導:編譯器會自動斷定你傳入的數據是什麼數據類型,而後將T改爲對應數據類型進行操做;內存

(2)本身聲明數據類型進行調用,具體實現以下:編譯器

    //一、自動類型推導
    swap(a, b);
    cout << "a=" << a << endl;
    cout << "b=" << b << endl;
    //二、顯示指定類型
    swap<int>(a, b);
    cout << "a=" << a << endl;
    cout << "b=" << b << endl;

什麼時候必須本身聲明數據類型呢?

那就是沒有參數傳遞的時候。好比知識一個打印函數,沒有參數傳遞,這裏就不寫代碼了。

三、多個虛類型
前面是針對一個函數裏面都是同一數據類型的,若是含有不一樣數據類型,假若有兩個:

template<class T1,class T2>
void func(T1 a,T2 b){....}
1
2
調用時能夠自動識別類型也能夠本身聲明數據類型:

func<int,double>(1,3.14);
1
3、類模板
前面已經介紹了模板大體的做用,這裏對類模板就不作過多說明,直接上乾貨:

一、定義
咱們定一個學生類

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;
}
二、調用
調用時必須指定輸入了什麼數據,也就是尖括號不能省略,這點與函數模板不同

Student<string,int,float>s("Tom",18,85.5);
1
4、類的函數模板
在類內定義的話就跟前面的函數模板同樣,若是在類外定義,類外也要寫上函數模板的形式:

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;
 }

5、類做爲數據類型傳入
//定義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;
}

6、類模板與繼承
若是父類是一個模板,子類繼承父類模板的時候,不知道父類模板內存是多少,編譯器就沒法給子類分配內存,解決方案是給子類也加上模板,方案以下:

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;
}

7、類模板與友元
前面也有過傳入類對象到函數裏面,若是這個函數須要用到對象裏面的數據,而該數據有被設定爲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;
}

以爲有用記得頂一下哦_  

相關文章
相關標籤/搜索