欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++超詳細講解泛型

 更新時間:2022年07月01日 08:48:17   作者:慕雪華年  
泛型編程,故如其名,是一個泛化的編程方式。其實現(xiàn)原理為程序員編寫一個函數(shù)/類的代碼示例,讓編譯器去填補出不同的函數(shù)實現(xiàn)

1.了解泛型編程

就好比活字印刷術(shù),可以靈活調(diào)整印刷的板塊和內(nèi)容,比只能固定印刷某一個內(nèi)容的雕版印刷術(shù)效率更高,也讓印刷術(shù)由此得到了更廣泛的應用。

在C++中,函數(shù)重載和模板的出現(xiàn),讓泛型編程得到了實際的應用。其中模板,就是類似活字印刷術(shù)一樣的存在。

2.函數(shù)模板

八八了那么多沒用的,讓我們來看看函數(shù)模板的語法實現(xiàn)吧

2.1簡單示例

下面是一個最簡單的交換函數(shù)的例子,通過標明模板參數(shù)T,讓編譯器自動識別函數(shù)傳參,并調(diào)用出不同的函數(shù)

template<typename T>
void Swap(T& left,T& right)
{
    T temp = left;
    left = right;
    right = temp;
}

其中,typename是定義模板的關(guān)鍵字,我們可以使用class來替代,但不能使用struct

可以看到,編譯器成功調(diào)用了Swap函數(shù),交換了int類型和double類型

2.2多個模板參數(shù)

如果我們嘗試把int和double同時傳參給這個函數(shù),會發(fā)生什么呢?

編譯器會報錯,表示模板參數(shù)T不明確

這時候我們有幾種解決方法

首先是將double強轉(zhuǎn)為int(反過來亦可)

你會發(fā)現(xiàn)還是不行,那是因為強轉(zhuǎn)并不支持用double引用int。所以我們把函數(shù)傳參中的引用去掉,即可正常調(diào)用這個函數(shù)(暫且不提傳引用和傳值的區(qū)別)

使用多個模板參數(shù)

和函數(shù)傳參類似,我們也可以設(shè)置多個模板參數(shù)

在下圖中,我使用typeid關(guān)鍵字來打印模板參數(shù)T1和T2的類型。

使用typeid需要包含頭文件#include <typeinfo>

可以看到,實際上函數(shù)在調(diào)用這個模板的時候,已經(jīng)實例化了這個函數(shù)(即替換模板參數(shù)為正確參數(shù)類型)這時候在后臺處理的時候,其實Show函數(shù)已經(jīng)實例化為了下面這個樣子

void Show(int left, double right)
{
    cout << typeid(left).name() << endl;
    cout << typeid(right).name() << endl;
}

2.3模板實例化

上面的方式,是編譯器自動幫我們實例化模板參數(shù)。在實際使用中,我們還可以自己指定實例化為什么類型

  • 利用強制類型轉(zhuǎn)換
  • 使用<int>直接指定實例化為int類型

使用第二種方式的時候,編譯器會對另外一個不匹配的參數(shù)進行隱式類型轉(zhuǎn)換。如果轉(zhuǎn)換不成功,則會報錯。

另外注意的是,函數(shù)模板參數(shù)T同樣可以用來作為返回值,但是不能通過返回值來推斷參數(shù)T的類型。比如下面這個函數(shù),我們在使用的時候就需要直接指定模板參數(shù)T,而不能寫一個int* ptr=test(10)讓編譯器通過“返回值是int*接收的,所以函數(shù)模板參數(shù)T是int”來推斷。

template<typename T>
T* test(int num)
{
	return new T[num];
}

函數(shù)模板支持給予參數(shù)缺省值

當一個參數(shù)不確定的時候,函數(shù)模板是支持給予缺省值的

template<typename T=char>
T* test(int num)
{
	return new T[num];
}

比如這樣,當我們沒有直接指定的時候,編譯器就會將T作為char類型,返回一個num大小的char(一個字節(jié))的空間

注意:當有多個模板參數(shù)時,缺省值需要從右往左給

函數(shù)模板的傳參也支持缺省值

template<typename T1>
void Add(T1 left, T1 right=10)
{
    cout << "Add temp "<<typeid(left).name() << " " << typeid(right).name() << endl;
    cout << left + right << endl << endl;
}
int main()
{
    int a=1;
    Add(a);
}

在這種情況下,編譯器會正確調(diào)用該函數(shù)模板

2.4模板和普通函數(shù)同時存在

以Add函數(shù)為例,在函數(shù)模板存在的同時,我們還可以單獨寫一個int類型的add函數(shù)。這都歸功于函數(shù)重載的存在。

同時,我們還可以使用<int>來指定函數(shù)模板重載為已存在的Add函數(shù)。因為本質(zhì)上這兩個函數(shù)是不同的,并不會沖突。

函數(shù)在調(diào)用的時候,首先會去調(diào)用已經(jīng)存在的函數(shù)。當參數(shù)和已存在的函數(shù)不匹配時,才會調(diào)用函數(shù)模板

2.5函數(shù)模板不支持定義和聲明分離

一般情況下,我們都會在頭文件中生命函數(shù),在另外一個源文件中定義函數(shù)。

但是模板是不支持這么做的!編譯器會報錯 鏈接錯誤

error LNK2019:無法解析的外部符號……

所以我們需要將函數(shù)模板的聲明和定義放在一個頭文件中。在部分使用場景,會使用.hpp來表示這個頭文件是包含了函數(shù)定義的(即.h和.cpp的集合體)。需要注意,這并不是一個硬性要求,你也可以直接使用.h,并將聲明和定義放入其中。

這是為什么呢?

因為單獨的.h聲明會在源文件頂部展開,而此時函數(shù)模板正常推演參數(shù),但編譯器并沒有找到函數(shù)的實現(xiàn),即這是一個沒有地址的函數(shù)。從而導致編譯器找不到函數(shù)的地址,產(chǎn)生了符號表的鏈接錯誤

有無解決辦法?

其實是有的,我們可以在模板函數(shù)定義的.cpp中對我們需要使用的函數(shù)進行顯式實例化指定

//頭文件
//聲明
template<typename T1>
void Add(T1 left, T1 right);
//源文件
//定義
template<typename T1>
void Add(T1 left, T1 right)
{
   cout << left + right << endl << endl;
}
//在源文件中顯式實例化
template
void Add<int>(int left, int right);
template
void Add<double>(double left, double right);

顯式實例化需要對我們要用的所有函數(shù)進行實例化,比如你需要用double類型,只顯示實例化了int類型是不行的,依舊會報錯。

這樣感覺非常多余……對吧!所以還是老老實實把聲明和定義放在同一個文件里面吧!

3.類模板

類模板的基本形式如下,這里作為一個小區(qū)分,我用class來當作模板參數(shù)名。實際上typename也是可以的

template<class T1, class T2, ...>class 類模板名{<!--{C}%3C!%2D%2D%20%2D%2D%3E-->// 類內(nèi)成員定義}; template<class T1, class T2, ...>
class 類模板名
{
// 類內(nèi)成員定義
};     

3.1簡單示例

下面用一個非常簡單的順序表代碼來演示一下類模板

template<class T>
class List
{
public:
    List(int capacity = 10)
        : _a(new T[capacity])
        , _size(0)
        , _capa(capacity)
    {}
 
    ~List();
    T& operator[](int pos)
    {
        assert(pos < _size);
        return _a[pos];
    }
private:
    T* _a;
    int _size;
    int _capa;
};
//類模板中函數(shù)放在類外進行定義時,需要加模板參數(shù)列表
template <class T>
List<T>::~List()
{
    delete[] _a;
    _size = _capa = 0;
}

可以看到,通過顯式實例化的方式,我們成功讓這個類模板變成了兩個不同類型的順序表

3.2成員函數(shù)聲明和定義分離

其中需要注意的是析構(gòu)函數(shù),聲明和定義分離的時候(同一文件),在定義的時候也需要加上模板參數(shù)

//類模板中函數(shù)放在類外進行定義時,需要加模板參數(shù)列表
template <class T>
List<T>::~List()
{
    delete[] _a;
    _size = _capa = 0;
}

個人覺得這樣也非常麻煩,既然模板最好是聲明和定義放在同一個文件,那還不如直接將類的成員函數(shù)直接定義到類內(nèi)部。多省事!

如果是聲明和定義放在不同文件中,顯式實例化方式如下

template
class List <int>;
template
class List <double>;

需要什么類型的類,就得實例化這個類型。

到此這篇關(guān)于C++超詳細講解泛型的文章就介紹到這了,更多相關(guān)C++泛型內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論