溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

C++語(yǔ)言學(xué)習(xí)(十七)——模板

發(fā)布時(shí)間:2020-06-11 07:24:36 來(lái)源:網(wǎng)絡(luò) 閱讀:3010 作者:天山老妖S 欄目:編程語(yǔ)言

C++語(yǔ)言學(xué)習(xí)(十七)——模板

一、模板簡(jiǎn)介

泛型(Generic Programming)即是指具有在多種數(shù)據(jù)類型上皆可操作的含意。 泛型編程的代表作品STL是一種高效、泛型、可交互操作的軟件組件。
泛型編程最初誕生于C++中,目的是為了實(shí)現(xiàn)C++的STL(標(biāo)準(zhǔn)模板庫(kù))。其語(yǔ)言支持機(jī)制就是模板(Templates)。模板的核心思想是參數(shù)化類型,即把一個(gè)原本特定于某個(gè)類型的算法或類當(dāng)中的類型信息抽掉,抽出來(lái)做成模板參數(shù)T。

二、函數(shù)模板

1、宏實(shí)現(xiàn)交換函數(shù)

定義一個(gè)交換兩個(gè)數(shù)的宏

#define SWAP(t, a, b)   \
do                      \
{                       \
    t c = a;            \
    a = b;              \
    b = c;              \
}while(0);

宏代碼塊實(shí)現(xiàn)的優(yōu)點(diǎn)是代碼復(fù)用,適合所有類型;缺點(diǎn)是缺少類型檢查。

2、函數(shù)重載實(shí)現(xiàn)

#include <iostream>
using namespace std;
void swap(int &a, int& b)
{
    int t = a;
    a = b;
    b = t;
}
void swap(double &a,double b)
{
    double t = a;
    a = b;
    b = t;
}
int main()
{
    int ia = 10; int ib = 20;
    swap(ia,ib);
    cout<<ia<<ib<<endl;
    double da = 10, db = 20;
    swap(da,db);
    cout<<da<<db<<endl;
    return 0;
}

函數(shù)重載實(shí)現(xiàn)的優(yōu)點(diǎn)是真正進(jìn)行函數(shù)調(diào)用,C++編譯器進(jìn)行類型檢查;缺點(diǎn)是根據(jù)類型重復(fù)定義函數(shù),無(wú)法代碼復(fù)用。

3、函數(shù)模板

函數(shù)模板是可用不同類型進(jìn)行調(diào)用的特殊函數(shù),關(guān)鍵在于類型參數(shù)化。
函數(shù)模板的語(yǔ)法格式如下:

template<typename/class 類型參數(shù)表>
返回類型 函數(shù)模板名(函數(shù)參數(shù)列表)
{
    函數(shù)模板定義體
}

template關(guān)鍵字用于聲明開始進(jìn)行泛型編程。
typename關(guān)鍵字用于聲明泛指類型。
函數(shù)模板可以自動(dòng)推導(dǎo)類型進(jìn)行調(diào)用,也可以顯示指定具體類型進(jìn)行調(diào)用。

4、函數(shù)模板實(shí)現(xiàn)

#include <iostream>
using namespace std;
template <typename T>
void Swap(T& a,T &b )
{
    T t = a;
    a = b;
    b = t;
}
int main()
{
    int ia = 10; int ib = 20;
    Swap(ia,ib); //Swap<int>(ia,ib);
    cout<<ia<<ib<<endl;
    double da = 10, db = 20;
    Swap(da,db); //Swap<double>(da,db);
    cout<<da<<db<<endl;
    string sa ="china"; string sb = "America";
    Swap(sa,sb);
    cout<<sa<<sb<<endl;
    return 0;
}

判斷一個(gè)變量是不是指針類型示例:

template 
<typename T>
bool isPtr(T *p) 
{
    return true;
}

template 
<typename T>
bool isPtr(T t)
{
    return false;
}

函數(shù)模板,只適用于函數(shù)的參數(shù)個(gè)數(shù)相同而類型不同,且函數(shù)體相同的情況。如果個(gè)數(shù)不同,則不能用函數(shù)模板。

5、函數(shù)模板分析

C++編譯器從函數(shù)模板通過(guò)具體類型產(chǎn)生不同的函數(shù),C++編譯器會(huì)對(duì)函數(shù)模板進(jìn)行兩次編譯,一次是函數(shù)模板代碼進(jìn)行編譯,一次是參數(shù)替換后的函數(shù)代碼進(jìn)行編譯。

#include <iostream>

using namespace std;

template <typename T>
void Swap(T& a, T& b)
{
    T c = a;
    a = b;
    b = c;
}

class Test
{

};

typedef void (*pFuncInt)(int&, int&);
typedef void (*pFuncDouble)(double&, double&);
typedef void (*pFuncTest)(Test&, Test&);

int main(int argc, char *argv[])
{
    pFuncInt pi = Swap;//Swap<int>
    printf("0x%x\n", pi);
    pFuncDouble pd = Swap;//Swap<double>
    printf("0x%x\n", pd);
    pFuncTest pt = Swap;//Swap<Test>
    printf("0x%x\n", pt);

    return 0;
}

函數(shù)模板本身不允許隱式類型轉(zhuǎn)換,因此,自動(dòng)推導(dǎo)類型時(shí)需要嚴(yán)格匹配,但當(dāng)顯示指定類型參數(shù)時(shí)可以進(jìn)行隱式類型轉(zhuǎn)換。
函數(shù)模板中的返回值類型必須顯示指定。


add<int>(ia,ib);

6、多類型參數(shù)函數(shù)模板

函數(shù)模板可以定義多個(gè)不同的類型參數(shù),但無(wú)法自動(dòng)推導(dǎo)返回值類型,可以從左向右部分指定類型參數(shù),實(shí)際工程中將返回值作為第一個(gè)類型參數(shù),必須顯式指定。

#include <iostream>
#include <string>

using namespace std;

template 
< typename T1, typename T2, typename T3 >
T1 Add(T2 a, T3 b)
{
    return static_cast<T1>(a + b);
}

int main()
{
    // T1 = int, T2 = double, T3 = double
    int r1 = Add<int>(0.5, 0.8);

    // T1 = double, T2 = float, T3 = double
    double r2 = Add<double, float>(0.5, 0.8);

    // T1 = float, T2 = float, T3 = float
    float r3 = Add<float, float, float>(0.5, 0.8);

    cout << "r1 = " << r1 << endl;     // r1 = 1
    cout << "r2 = " << r2 << endl;     // r2 = 1.3
    cout << "r3 = " << r3 << endl;     // r3 = 1.3

    return 0;
}

7、普通函數(shù)與函數(shù)模板的關(guān)系

函數(shù)模板可以被重載,C++編譯器優(yōu)先考慮普通函數(shù),但如果函數(shù)模板可以產(chǎn)生更好的匹配,則使用函數(shù)模板,可以通過(guò)空模板實(shí)參列表限定只能使用函數(shù)模板。

#include <iostream>
#include <string>

using namespace std;

template < typename T >
T Max(T a, T b)
{
    cout << "T Max(T a, T b)" << endl;

    return a > b ? a : b;
}

int Max(int a, int b)
{
    cout << "int Max(int a, int b)" << endl;

    return a > b ? a : b;
}

template < typename T >
T Max(T a, T b, T c)
{
    cout << "T Max(T a, T b, T c)" << endl;

    return Max(Max(a, b), c);
}

int main()
{
    int a = 1;
    int b = 2;

    cout << Max(a, b) << endl;                   // 普通函數(shù) Max(int, int)

    cout << Max<>(a, b) << endl;                 // 函數(shù)模板 Max<int>(int, int)

    cout << Max(3.0, 4.0) << endl;               // 函數(shù)模板 Max<double>(double, double)

    cout << Max(5.0, 6.0, 7.0) << endl;          // 函數(shù)模板 Max<double>(double, double, double)

    cout << Max('a', 100) << endl;               // 普通函數(shù) Max(int, int)

    return 0;
}

三、類模板

1、類模板的定義

C++語(yǔ)言中將模板的思想應(yīng)用于類,使得類的實(shí)現(xiàn)不關(guān)注數(shù)據(jù)元素的具體類型,只關(guān)注類需要實(shí)現(xiàn)的功能。
類模板的定義語(yǔ)法如下:

template <typename T>
class classname
{

};

在類聲明前使用template進(jìn)行標(biāo)識(shí),&lt;typename T&gt;用于說(shuō)明類中使用泛指類型T。
類內(nèi)定義成員函數(shù)

template<typename T>
class classname
{
public:
    void push(int size)
    {
}
}

類外定義函數(shù)

template<typename T>
void classname<T>::push(T data)
{
}

類模板實(shí)例化為模板類:


classname<double> object;

類模板是類的抽象,類是類模板的實(shí)例。

2、類模板應(yīng)用

類模板只能顯示指定類型參數(shù),無(wú)法自動(dòng)推導(dǎo)。聲明的泛型類型參數(shù)可以出現(xiàn)在類模板的任意地方。
類模板必須在頭文件中實(shí)現(xiàn),不能分開實(shí)現(xiàn)在不同文件中。類模板的成員函數(shù)需要定義在外部定義時(shí),每個(gè)成員函數(shù)需要加上類模板template&lt;typename T&gt;聲明。
類模板適合以相同的邏輯處理不同的數(shù)據(jù)類型的數(shù)據(jù),因此非常適合編寫數(shù)據(jù)結(jié)構(gòu)相關(guān)代碼。

#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
using namespace std;
template<typename T>
class Stack
{
public:
    Stack(int size)
    {
        space = new T[size];
        top = 0;
    }
    ~Stack();
    bool isEmpty();
    bool isFull();
    void push(T data);
    T pop();
private:
    T* space;
    int top;
};
template<typename T>
Stack<T>::~Stack()
{
    delete []space;
}
template<typename T>
bool Stack<T>::isEmpty()
{
    return top == 0;
}
template<typename T>
bool Stack<T>::isFull()
{
    return top == 1024;
}
template<typename T>
void Stack<T>::push(T data)
{
    space[top++] = data;
}
template<typename T>
T Stack<T>::pop()
{
    return space[--top];
}
int main()
{
    Stack<double> s(100); //Stack<string> s(100);
    if(!s.isFull())
        s.push(10.3);
    if(!s.isFull())
        s.push(20);
    if(!s.isFull())
        s.push(30);
    if(!s.isFull())
        s.push(40);
    if(!s.isFull())
        s.push(50);
    while(!s.isEmpty())
        cout<<s.pop()<<endl;
    return 0;
}

3、類模板分析

類模板通過(guò)具體類型產(chǎn)生不同的類,C++編譯器在類模板聲明的地方對(duì)類模板代碼本身進(jìn)行編譯,在使用的地方對(duì)類模板參數(shù)替換后產(chǎn)生的代碼進(jìn)行編譯。
類模板可以定義多個(gè)不同類型參數(shù)。

#include <iostream>
#include <string>

using namespace std;

template <typename T>
class Operator
{
public:
    Operator()
    {
        cout << "Operator()" << endl;
    }
    T add(T a, T b)
    {
        cout << "T add(T a, T b)" << endl;
        return a + b;
    }
    T minus(T a, T b)
    {
        return a - b;
    }
    T multiply(T a, T b)
    {
        return a * b;
    }
    T divide(T a, T b)
    {
        return a / b;
    }
};

int main(int argc, char *argv[])
{
    Operator<int> op1;
    cout << op1.add(1, 2) << endl;
    cout << op1.add(1, 2) << endl;

    Operator<string> op2;

    cout << op2.add("D.T.", "Software") << endl;

    return 0;
}
// output:
// Operator()
// T add(T a, T b)
// 3
// Operator()
// T add(T a, T b)
// 3
// Operator()
// T add(T a, T b)
// Hello World

上述代碼中,類模板中的函數(shù)代碼在使用的時(shí)候才會(huì)被分別編譯。

四、模板的特化

1、類模板的特化

類模板可以被特化,以下情況需要特化類模板:
A、指定特定類型的實(shí)現(xiàn)
B、部分參數(shù)類型必須顯示指定
C、根據(jù)類型參數(shù)分開實(shí)現(xiàn)類模板
類模板的特化分為部分特化和完全特化。部分特化是指用特定規(guī)則約束類型參數(shù),完全特化是指完全顯示指定類型參數(shù)。
類模板的特化是模板的分開實(shí)現(xiàn),本質(zhì)上是同一個(gè)類模板,特化類模板必須顯示指定每一個(gè)類型參數(shù)。編譯器會(huì)自動(dòng)優(yōu)先選擇特化類模板。

#include <iostream>

using namespace std;

template
<typename T1, typename T2>
class Test
{
public:
    void add(T1 a, T2 b)
    {
        cout << "void add(T1 a, T2 b)" << endl;
        cout << a + b << endl;
    }
};

//部分特化
template
<typename T>
class Test<T,T>
{
public:
    void add(T a, T b)
    {
        cout << "void add(T a, T b)" << endl;
        cout << a + b << endl;
    }
    void print()
    {
        cout << "class Test <T,T>" << endl;
    }
};

//完全特化
template
<>
class Test<int,int>
{
public:
    void add(int a, int b)
    {
        cout << "void add(int a, int b)" << endl;
        cout << a + b << endl;
    }
    void print()
    {
        cout << "class Test<int,int>" << endl;
    }
};

int main(int argc, char *argv[])
{
    Test<int, int> t1;//完全特化
    t1.add(1,2);
    t1.print();

    Test<double, double> t2;//部分特化
    t2.add(3.14,2.0);
    t2.print();

    Test<float, double> t3;//類模板
    t3.add(3.14,2.0);

    return 0;
}

// output:
// void add(int a, int b)
// 3
// class Test<int,int>
// void add(T a, T b)
// 5.14
// class Test <T,T>
// void add(T1 a, T2 b)
// 5.14

2、函數(shù)模板的特化

函數(shù)模板只支持模板的完全特化。

#include <iostream>

using namespace std;

//函數(shù)模板
template
<typename T>
bool Equal(T a, T b)
{
    cout << "bool Equal(T a, T b)" << endl;
    return a == b;
}

//函數(shù)特化模板
template
< >
bool Equal<double>(double a, double b)
{
    const double delta = 0.00000000000001;
    double r = a - b;
    cout << "bool Equal<double>(double a, double b)" << endl;
    return (-delta < r) && (r < delta);
}

//函數(shù)重載
bool Equal(double a, double b)
{
    const double delta = 0.00000000000001;
    double r = a - b;
    cout << "bool Equal(double a, double b)" << endl;
    return (-delta < r) && (r < delta);
}

int main(int argc, char *argv[])
{
    Equal<double>(0.1,0.1);//函數(shù)特化模板
    Equal<int>(10,10);//函數(shù)模板
    Equal(0.1,0.1);//函數(shù)重載

    return 0;
}

// output:
// bool Equal<double>(double a, double b)
// bool Equal(T a, T b)
// bool Equal(double a, double b)

工程實(shí)踐中當(dāng)需要重載函數(shù)模板時(shí),優(yōu)先使用函數(shù)模板特化,當(dāng)函數(shù)模板特化無(wú)法滿足需求時(shí),使用函數(shù)重載。

五、數(shù)組類模板

1、數(shù)值型模板

模板參數(shù)可以是數(shù)值型參數(shù),數(shù)值型模板參數(shù)存在限制:
A、變量不能作為模板參數(shù)
B、浮點(diǎn)數(shù)不能作為模板參數(shù)
C、類對(duì)象不能作為模板參數(shù)
模板參數(shù)是在編譯階段處理的,因此在編譯階段需要唯一確定。
使用最高效方式求1+2+3+4......+100

#include <iostream>
using namespace std;
template
<int N>
class Sum
{
public:
    static const int value = Sum<N-1>::value + N;
};

template
<>
class Sum<1>
{
public:
    static const int value = 1;
};

int main(int argc, char *argv[])
{
    cout<<Sum<100>::value<<endl;
    return 0;
}

2、數(shù)組模板

#ifndef _ARRAY_H_
#define _ARRAY_H_

template
< typename T, int N >
class Array
{
    T m_array[N];
public:
    int length();
    bool set(int index, T value);
    bool get(int index, T& value);
    T& operator[] (int index);
    T operator[] (int index) const;
    virtual ~Array();
};

template
< typename T, int N >
int Array<T, N>::length()
{
    return N;
}

template
< typename T, int N >
bool Array<T, N>::set(int index, T value)
{
    bool ret = (0 <= index) && (index < N);
    if( ret )
    {
        m_array[index] = value;
    }
    return ret;
}

template
< typename T, int N >
bool Array<T, N>::get(int index, T& value)
{
    bool ret = (0 <= index) && (index < N);
    if( ret )
    {
        value = m_array[index];
    }
    return ret;
}

template
< typename T, int N >
T& Array<T, N>::operator[] (int index)
{
    return m_array[index];
}

template
< typename T, int N >
T Array<T, N>::operator[] (int index) const
{
    return m_array[index];
}

template
< typename T, int N >
Array<T, N>::~Array()
{

}

#endif

六、智能指針類模板

智能指針是C++開發(fā)庫(kù)的重要類模板之一,是自動(dòng)內(nèi)存管理的主要手段,可以避開內(nèi)存的相關(guān)問(wèn)題。

1、STL的智能指針

STL中的智能指針?lè)譃閍uto_ptr、shared_ptr、weak_ptr、unique_ptr四類。
auto_ptr智能指針的特性:
A、生命周期結(jié)束時(shí),銷毀指向的內(nèi)存空間
B、不能指向堆數(shù)組,只能指向堆對(duì)象
C、一塊堆空間只能屬于一個(gè)智能指針
D、多個(gè)智能指針對(duì)象不能指向同一塊空間
shared_ptr智能指針的特性:
帶有引用計(jì)數(shù)機(jī)制,支持多個(gè)指針指向同一對(duì)象內(nèi)存空間。
weak_ptr智能指針的特性:
weak_ptr是一種弱引用,指向shared_ptr所管理的對(duì)象。
unique_ptr智能指針的特性:
一個(gè)指針對(duì)象指向一片內(nèi)存空間,不能拷貝構(gòu)造和賦值

STL智能指針使用實(shí)例:

#include <iostream>
#include <memory>

using namespace std;

class Test
{
    string m_name;
public:
    Test(const char* name)
    {
        cout << "Hello, " << name << "." << endl;
        m_name = name;
    }

    void print()
    {
        cout << "I'm " << m_name << "." << endl;
    }

    ~Test()
    {
        cout << "Goodbye, " << m_name << "." << endl;
    }
};

int main(int argc, char *argv[])
{
    auto_ptr<Test> pt(new Test("D.T.Software"));
    cout << "pt = " << pt.get() << endl;
    pt->print();
    cout << endl;

    auto_ptr<Test> pt1(pt);
    cout << "pt = " << pt.get() << endl;//NULL
    cout << "pt1 = " << pt1.get() << endl;//

    return 0;
}

2、QT中的智能指針

QT中的主要智能指針有:QPointer、QSharedPointer、QWeakPointer、QScopedPointer、QSharedDataPoiner、QExplicitlySharedDataPointer。
QPointer智能指針特性:
A、當(dāng)其所指向的對(duì)象被銷毀時(shí)會(huì)被自動(dòng)置空
B、析構(gòu)時(shí)不會(huì)自動(dòng)銷毀所指向的對(duì)象
多個(gè)QPointer指針對(duì)象可以指向同一內(nèi)存空間,當(dāng)所指向?qū)ο蟊讳N毀時(shí)指針會(huì)被自動(dòng)置空,但是指針對(duì)象析構(gòu)時(shí)不會(huì)自動(dòng)銷毀所指向的對(duì)象。
QSharedPointer智能指針特性:
A、引用計(jì)數(shù)型智能指針
B、可以被自由的拷貝和賦值
C、當(dāng)引用計(jì)數(shù)為0時(shí)才刪除指向的對(duì)象
QT中智能指針使用實(shí)例:

#include <QPointer>
#include <QSharedPointer>
#include <QDebug>

class Test : public QObject
{
    QString m_name;
public:
    Test(const char* name)
    {
        qDebug() << "Hello, " << name << ".";

        m_name = name;
    }

    void print()
    {
        qDebug() << "I'm " << m_name << ".";
    }

    ~Test()
    {
        qDebug() << "Goodbye, " << m_name << ".";
    }
};

int main()
{
    QPointer<Test> pt(new Test("D.T.Software"));
    QPointer<Test> pt1(pt);
    QPointer<Test> pt2(pt);//多個(gè)QPointer指針對(duì)象可以指向同一內(nèi)存空間

    pt->print();
    pt1->print();
    pt2->print();

    delete pt;//QPointer智能指針指向的對(duì)象被銷毀時(shí),指針對(duì)象被置空

    qDebug() << "pt = " << pt;//NULL
    qDebug() << "pt1 = " << pt1;//NULL
    qDebug() << "pt2 = " << pt2;//NULL

    qDebug() << endl;

    QSharedPointer<Test> spt(new Test("Delphi Tang"));
    QSharedPointer<Test> spt1(spt);
    QSharedPointer<Test> spt2(spt);

    spt->print();
    spt1->print();
    spt2->print();

    return 0;//指針對(duì)象都被銷毀時(shí)引用計(jì)數(shù)為0,自動(dòng)析構(gòu)指針指向的對(duì)象
}

3、智能指針類模板

#ifndef _SMARTPOINTER_H_
#define _SMARTPOINTER_H_

template
< typename T >
class SmartPointer
{
    T* mp;
public:
    SmartPointer(T* p = NULL)
    {
        mp = p;
    }

    SmartPointer(const SmartPointer<T>& obj)
    {
        mp = obj.mp;
        const_cast<SmartPointer<T>&>(obj).mp = NULL;
    }

    SmartPointer<T>& operator = (const SmartPointer<T>& obj)
    {
        if( this != &obj )
        {
            delete mp;
            mp = obj.mp;
            const_cast<SmartPointer<T>&>(obj).mp = NULL;
        }

        return *this;
    }

    T* operator -> ()
    {
        return mp;
    }

    T& operator * ()
    {
        return *mp;
    }

    bool isNull()
    {
        return (mp == NULL);
    }

    T* get()
    {
        return mp;
    }

    ~SmartPointer()
    {
        delete mp;
    }
};

#endif

七、單例類模板

某些類在整個(gè)系統(tǒng)的生命周期中只能有一個(gè)對(duì)象存在,即單例模式。
要控制類的對(duì)象數(shù)目必須隱藏類的構(gòu)造函數(shù),即構(gòu)造函數(shù)聲明為private。
定義一個(gè)instance標(biāo)識(shí)符,初始化為NULL,當(dāng)需要使用對(duì)象時(shí)查看instance的值,如果instance為NULL則創(chuàng)建對(duì)象并用instance標(biāo)識(shí),如果instance非空則返回instance標(biāo)識(shí)的值。

#ifndef _SINGLETON_H_
#define _SINGLETON_H_

template
< typename T >
class Singleton
{
    static T* c_instance;
public:
    static T* GetInstance();
};

template
< typename T >
T* Singleton<T>::c_instance = NULL;

template
< typename T >
T* Singleton<T>::GetInstance()
{
    if( c_instance == NULL )
    {
        c_instance = new T();
    }

    return c_instance;
}

#endif

使用代碼:

#include <iostream>
#include <string>
#include "Singleton.h"

using namespace std;

class SObject
{
    friend class Singleton<SObject>;    // 當(dāng)前類需要使用單例模式

    SObject(const SObject&);
    SObject& operator= (const SObject&);

    SObject()
    {
    }
public:

    void print()
    {
        cout << "this = " << this << endl;
    }
};

int main()
{
    SObject* s = Singleton<SObject>::GetInstance();
    SObject* s1 = Singleton<SObject>::GetInstance();
    SObject* s2 = Singleton<SObject>::GetInstance();

    s->print();
    s1->print();
    s2->print();

    return 0;
}

八、模板應(yīng)用示例

判斷一個(gè)變量是不是指針
C++編譯器匹配的調(diào)用優(yōu)先級(jí):
A、重載函數(shù)
B、函數(shù)模板
C、變參函數(shù)
可以根據(jù)C++編譯器匹配的調(diào)用優(yōu)先級(jí),將函數(shù)模板匹配指針變量,返回true,變參函數(shù)匹配非指針變量,返回false。

template
<typename T>
bool IsPtr(T *pt)
{
    return true;
}

bool IsPtr(...)
{
    return false;
}

但是,由于變參函數(shù)是C語(yǔ)言的內(nèi)容,無(wú)法解析C++自定義類型對(duì)象,可能造成程序崩潰。

template
<typename T>
char IsPtr(T* v) // match pointer
{
    return 'd';
}

int IsPtr(...)  // match non-pointer
{
    return 0;
}

#define ISPTR(p) (sizeof(IsPtr(p)) == sizeof(char))

上述代碼中,C++編譯器在編譯時(shí)會(huì)進(jìn)行函數(shù)匹配,不會(huì)進(jìn)行調(diào)用,避免了參數(shù)為自定義對(duì)象時(shí)調(diào)用變參函數(shù)導(dǎo)致的程序崩潰。

九、class與typename關(guān)鍵字

C++語(yǔ)言在引入了面向?qū)ο缶幊趟枷霑r(shí),使用class關(guān)鍵字定義類類型。C++語(yǔ)言發(fā)展過(guò)程中引入了泛型編程,直接復(fù)用class關(guān)鍵字來(lái)定義模板。但泛型編程針對(duì)的不只是類類型,直接復(fù)用class關(guān)鍵字會(huì)使代碼出現(xiàn)二義性。因此,C++直接引入了typename關(guān)鍵字,用于在模板定義中聲明泛指類型,明確告訴C++編譯器聲明的標(biāo)識(shí)符為類型。
C++語(yǔ)言中允許類定義中嵌套類型,因此當(dāng)自定義類類型中嵌套類型的標(biāo)識(shí)符與其它類類型中定義的成員變量標(biāo)識(shí)符重名時(shí)將會(huì)造成二義性。不同類中的同名標(biāo)識(shí)符代表可能導(dǎo)致二義性,因此C++編譯器無(wú)法識(shí)別標(biāo)識(shí)符的確切意義。

#include <iostream>

using namespace std;

class Test1
{
public:
    static const int NS = 1;
};

class Test2
{
public:
    struct NS
    {
        int value;
    };
};

int a = 0;

template <class T>
void func()
{
    T::NS* a;
}

int main(int argc, char *argv[])
{
    func<Test1>();
    //func<Test2>();//error
    //error: dependent-name 'T:: NS' is parsed as a non-type,
    //but instantiation yields a type
    //say 'typename T:: NS' if a type is meant

    return 0;
}

上述代碼中,C++編譯器不會(huì)將func函數(shù)模板中NS解析為類型,因此使用Test2作為參數(shù)時(shí),C++編譯器會(huì)報(bào)錯(cuò)。因此,為了將NS明確聲明為類型,需要使用typename關(guān)鍵字對(duì)NS標(biāo)識(shí)符進(jìn)行聲明。代碼如下:

#include <iostream>

using namespace std;

class Test1
{
public:
    static const int NS = 1;
};

class Test2
{
public:
    struct NS
    {
        int value;
    };
};

int a = 0;

template <class T>
void func()
{
    typename T::NS* a;
}

int main(int argc, char *argv[])
{
    //func<Test1>();//error
    func<Test2>();
    return 0;
}

上述代碼中,NS被明確聲明為類型,因此如果使用Test1作為參數(shù),func函數(shù)模板將會(huì)報(bào)錯(cuò)。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI