模板類的繼承問題

fantasy_linux發表於2016-04-22

   首先大家來看這段程式碼:

class A 
{
public:
    void Show()
    {
        cout << "A::Show() !!!" << endl;
    }
    void Fun()
    {
        cout << "A::Fun() !!! " << endl;
    }
};


class B 
{
public:
    void Show()
    {
        cout << "B::Show() !!!" << endl;
    }
    void Fun()
    {
        cout << "B::Fun() !!! " << endl;
    }
};


class C 
{
public:
    void Show()
    {
        cout << "C::Show() !!!" << endl;
    }
    void Fun()
    {
        cout << "C::Fun() !!! " << endl;
    }
};

template<typename Com>
class Test
{
public:
    void send()
    {
        Com c;
        c.Show();
        c.Fun();
    }
    void Show()
    {
        cout << "Test::Show() !!!" << endl;
    }
};

int main(int argc,char**argv)
{
    Test<A> t1;
    t1.send();
    t1.Show();
    cout << endl;

    Test<B> t2;
    t2.send();
    t2.Show();
    cout << endl;


    Test<C> t3;
    t3.send();
    t3.Show();
    cout << endl;

    return 0;
}

我們先來大概分析一下這段沒有實際意義的程式碼:

     首先定義了類A,類B,類C,這三個類都具有Show方法和Fun方法,只不過具體的實現不同。接著又定義了模板類Test。

下來我們看程式的執行結果:

     

上面的程式碼我們並沒有使用繼承,通過模板類Test的型別,使得函式的呼叫不同。。。

   下面我們來看如何通過繼承來實現:

class A 
{
public:
    void Show()
    {
        cout << "A::Show() !!!" << endl;
    }
    void Fun()
    {
        cout << "A::Fun() !!! " << endl;
    }
};


class B 
{
public:
    void Show()
    {
        cout << "B::Show() !!!" << endl;
    }
    void Fun()
    {
        cout << "B::Fun() !!! " << endl;
    }
};


class C 
{
public:
    void Show()
    {
        cout << "C::Show() !!!" << endl;
    }
    void Fun()
    {
        cout << "C::Fun() !!! " << endl;
    }
};

template<typename Com>
class Test
{
public:
    void send()
    {
        Com c;
        c.Show();
        c.Fun();
    }
    void Show()
    {
        cout << "Test::Show() !!!" << endl;
    }
};

template<typename Com>
class Derived: public Test<Com>
{
public:
    //第一種方式:
    //使用using 宣告式
    #if 0
    using Test<Com>::send;
    using Test<Com>::Show;
    void fun()
    {
        cout << "Derived::fun() !!!" << endl;
        Show();
        send();
    }
    #endif

    //第二種方式
    #if 0
    void fun()
    {
        cout << "Derived::fun() !!!" << endl;
        this->Show();
        this->send();

    }
    #endif
    //第三種方式
    #if 1
    void fun()
    {
        cout << "Derived::fun() !!!" << endl;
        Test<Com>::Show();
        Test<Com>::send();

    }
    
    #endif
};

int main(int argc,char**argv)
{
    Derived<A> t1;
    t1.fun();
    cout << endl;


    Derived<B> t2;
    t2.fun();
    cout << endl;


    Derived<C> t3;
    t3.fun();
    cout << endl;

    return 0;
}

如果我們把上述Derived類中的fun函式改寫成如下的形式:

void fun()
    {
        cout << "Derived::fun() !!!" << endl;
        Show();
        send();

    }
    

那麼這段程式碼編譯器是無法通過編譯的。編譯器則抱怨Show方法和send方法不存在。但是我們明明在基類Test中定義了,編譯器卻看不到它們,這是為什麼呢?

     這個問題在於,當編譯器遭遇class template Derived定義式時,並不知道它繼承什麼樣的class。當然它繼承的是Test<Com>,但其中Com是個template引數,不到後來(當Derived被具體化)無法確切知道它是什麼。而如果不知道Com是什麼,就無法知道class Test<Com>看起來像什麼-----更明確的說是沒辦法知道它是否有個send方法和Show方法。。

    我們可以有三種方式解決這個問題:

     (1)在base class函式呼叫動作之前加上“this ->”。

     (2)使用using宣告式。

     (3)明確的指出被呼叫的函式位於base class內。

   

在上面的程式中也體現出來了。。。

下面我們給出程式的執行結果:

   下來我們考慮這個問題,如果現在有個類D,它只有一個Fun方法,並沒有Show的方法。這時我們需要為類D產生一個Test的特化版,具體的實現如下:

class A 
{
public:
    void Show()
    {
        cout << "A::Show() !!!" << endl;
    }
    void Fun()
    {
        cout << "A::Fun() !!! " << endl;
    }
};


class B 
{
public:
    void Show()
    {
        cout << "B::Show() !!!" << endl;
    }
    void Fun()
    {
        cout << "B::Fun() !!! " << endl;
    }
};


class C 
{
public:
    void Show()
    {
        cout << "C::Show() !!!" << endl;
    }
    void Fun()
    {
        cout << "C::Fun() !!! " << endl;
    }
};

class D
{
public:
    void Fun()
    {
        cout << "D::Fun() !!!" << endl;
    }
};


template<typename Com>
class Test
{
public:
    Test<Com>()
    {cout << "Test<Com>:: " << endl;}
public:
    void send()
    {
        Com c;
        c.Show();
        c.Fun();
    }
    void Show()
    {
        cout << "Test::Show() !!!" << endl;
    }
    
};


template<>
class Test<D>
{
public:
    Test<D>()
    {cout << "Test<D>:: " << endl;}
public:
    void send()
    {
        D c;
        c.Fun();
    }
    
    void Show()
    {
        cout << "Test::Show() !!!" << endl;
    }
    
};


template<typename Com>
class Derived: public Test<Com>
{
public:
    //第一種方式:
    //使用using 宣告式
    #if 0
    using Test<Com>::send;
    using Test<Com>::Show;
    void fun()
    {
        cout << "Derived::fun() !!!" << endl;
        Show();
        send();
    }
    #endif

    //第二種方式
    #if 1
    void fun()
    {
        cout << "Derived::fun() !!!" << endl;
        this->Show();
        this->send();

    }
    #endif
    //第三種方式
    #if 0
    void fun()
    {
        cout << "Derived::fun() !!!" << endl;
        Test<Com>::Show();
        Test<Com>::send();

    }
    
    #endif
};
int main(int argc,char**argv)
{
    Derived<A> t1;
    t1.Show();
    t1.send();
    cout << endl;

    Derived<B> t2;
    t2.Show();
    t2.send();
    cout << endl;

    Derived<C> t3;
    t3.Show();
    t3.send();
    cout << endl;

    Derived<D> t4;
    t4.Show();
    t4.send();
    cout << endl;

    
    return 0;
}


注:程式中標紅的就是一個特化版的Test template,“template<>”語法象徵這既不是template也不是標準class,在template實參是D時被使用。這就是所謂的模板全特化。

  我們來看程式的執行結果:

  模板類在繼承時,可在derived class template內通過"this ->"指涉base class template內的成員名稱,或籍由一個明白寫出的“base class 資格修飾符”完成。








相關文章