關於C++ template類的友元函數的六種情況的分析

#include <iostream>
/*
 *
 * 
    template<class T> class task;
    template<class T> task<T>* preempt(task<T>*);

    template<class T> class task {
    friend void next_time();
    friend void process(task<T>*);
    friend task<T>* preempt<T>(task<T>*);
    template<class C> friend int func(C);
    friend class task<int>;
    template<class P> friend class frd;
    };

 *其實理解,類模板的友元函數,首先得明白如何聲明友元函數,以及類模板如何被實例化的。
 *首先說下類模板是如何被實例化的,類模板要想被實例化,就必須得藉助模板參數列表提供的
 *參數類型,比方說我下面的base類模板,我就必須得到base<int> a;的時候纔會產生相應的類
 *這個時候要注意,只有模板類被實例化的時候,這個類纔是被真正的實現的,以前沒實例化的
 *時候,只是一些聲明而已;所以實例化以後我們纔可以看到什麼類型的友元被聲明瞭。拿上面
 *的例子來說的話,在模板類task中定義了好幾種不同的友元。
 *第一個友元next_time()是一個普通的函數,所以,當我們實例化不同的類型的task實例的時候,
 *都會在各自的實例中聲明該函數爲友元函數,所以在所有的task實例中我們的next_time()都被
 *聲明成了一個友元函數。但是請注意這個申請爲友元函數的過程,其實是在task的各自實例化
 *過程中聲明的,而不是一次就聲明的,也就是說我的每一個task實例對應聲明一個next_time()
 *友元函數而已;接着看第二個友元,這個友元的形參是一個模板類task的指針。那它是怎麼一
 *回事呢?當我們實例化一個task<int>時(就拿int來說)。那麼我的process的形參就被實例化成
 *task<int> *的類型了。所以也就是說,我的process是一對一的友元函數類型。即,我的task<int>
 *聲明的是process(task<int> *)這個函數爲友元。所以你的process(task<T> *)就得定義很多實際
 *類型的函數。這個時候你只能使用重載函數的方式去定義各個類型process的函數。不能使用
 *模板去實現這個重載的過程,因爲這個process函數是一個普通的函數;接着看第三個友元。
 *task<T>* preempt<T>(task<T> *);這個是一個模板函數作爲一個友元。注意這個時候友元沒有那個
 *template<typename T>因爲在這個類作用域內已經有了T了。所以不用定義並且,如果你使用
 *template<T>的話也會報錯,因爲不能在同一個作用域內定義兩個相同名的類型參數。好了,繼續看
 *第三個友元。當我們實例化一個task類時,我們也順便實例話了一個preempt相同類型的函數。也就
 *是說,第三個友元類表示的是我們實例化一個類型的task的時候,我們順便實例化了一個相同類型的
 *模板函數,該實例化的模板函數被聲明成該類型的task的友元類。那這個與第二個有什麼區別呢?
 *因爲第二個是一個普通的函數,所以你得重載相應類型的函數纔可以去匹配相應類型的task類。但是
 *第三個因爲是一個模板函數。所以你可以定義這個模板,當定義一個int類型的task實例的時候,你只需要
 *實例化你的preempt<int>爲int類型的就可以了。這樣就可以去訪問你的int類型的task實例了。但是
 *請注意,因爲你的int類型的task只聲明瞭int類型的preempt爲友元,所以你只能使用int類型的preempt
 *去訪問int類型的task。如果使用不同類型的preempt,那麼就不可以,會報找不到匹配的友元函數的。
 *接着看第四個友元。這個友元表示的是一個模板函數,不過這個模板函數的模板參數列表是與類的模板參數
 *列表不一樣的。所以這個時候。當你實例化一個int類型的task的時候,它聲明一個模板函數(這個模板的
 *參數列表是與類的參數列表不一樣)func爲友元。所以這個友元函數表示的範圍更大了。也就是說,
 *當我們實例化一個int類型的task的時候,我們的模板func函數被聲明成了一個友元。所以只要我實例化一個
 *func,就可以去訪問一個int類型的task。不管我的func被實例化成什麼類型,即使是double(與int不一樣的類型)
 *類型實例化的func也可以去訪問int類型實例化的task。所以第四個表示的是,我們只要實例化一個類型的task,
 *那麼我的所有實例化的func都可以訪問被實例化的task(但是隻有被實例化task的對象纔可以)。接着看第五個
 *友元。第五個class task<int>表示的是一個友元模板類,不過這個模板類已經被實例化了。所以,當我們實例化
 *一個double類型的task時,我們的task<int>類就被聲明成一個友元類了。所以只要實例化一個類型的task,那麼
 *我的task<int>模板類就被聲明成相應的友元函數了。也就是說我的task<int>模板類可以是任意被實例化的task
 *的友元類;但是注意,只有task<int>是別的被實例化的task累的友元,其他類型的就不是了。接着看第六個友元。
 *template<class P> friend class frd;這個也是一個模板類。但是注意,這個模板類的模板參數列表和類task
 *的模板參數列表不一樣。也就是當我們實例化一個int類型的task時,我們的frd模板類被聲明成了一個友元類。這個
 *跟不同參數列表的模板函數是一樣的。所以我的任意類型的frd實例是任意被實例化task的友元類了。這也就是多對多的
 *關係了。
 *
 */

template<typename> class task;
template<typename> class percent;
template<typename T> void preempt(const task<T> &);
template<typename T> class frd;


template<typename T>class task{
friend void next_time();//普通函數,形參與task無關
friend void process(const task<T> &);//普通函數,形參與task有關
friend void preempt<T>(const task<T> &);//模板函數,形參與task有關
template<typename C> friend void func(C);//模板函數,模板參數列表不一樣
friend class percent<int>;
template<typename P> friend class frd;
public:
    task(T a):number(a){}
    void print(){
        std::cout<<"this is the base "<<number<<std::endl;
    }
private:
    T number;
};


//next_time ,這個函數可以訪問任何被實例化的task,也就是所有被實例化的task都將next_time
void next_time(){
    task<int>a(10);
    task<double>b(20.4);
    task<char>c('h');
    std::cout<<"this is the function "<<__FUNCTION__<<" and this is the a.number "<<a.number<<std::endl;
    std::cout<<"this is the function "<<__FUNCTION__<<" and this is the b.number "<<b.number<<std::endl;
    std::cout<<"this is the function "<<__FUNCTION__<<" and this is the c.number "<<c.number<<std::endl;
}

//void process(const task<T> &);
//下面的這些必須我們去手動重載的
void process(const task<int> &a){
    std::cout<<"this is the funcion "<<__FUNCTION__<<" and this is the a.number "<<a.number<<std::endl;
}
void process(const task<double> &a){
    std::cout<<"this is the funcion "<<__FUNCTION__<<" and this is the a.number "<<a.number<<std::endl;
}
void process(const task<char> &a){
    std::cout<<"this is the funcion "<<__FUNCTION__<<" and this is the a.number "<<a.number<<std::endl;
}

//第三個友元的實現
//template<typename T> void preempt(const task<T> &)
template<typename T> void preempt(const task<T> &a){
    std::cout<<"this is the funcion "<<__FUNCTION__<<" and this is the a.number "<<a.number<<std::endl;
}

//第四個友元的實現
//template<typename C> friend void func();
//其實這個友元和第一個友元是異曲同工的做法,這裏不在演示了
template<typename C> void func(C number){
    task<int>a(10);
    task<double>b(20.4);
    task<char>c('h');
    std::cout<<"this is the function "<<__FUNCTION__<<" and this is the a.number "<<a.number<<std::endl;
    std::cout<<"this is the function "<<__FUNCTION__<<" and this is the b.number "<<b.number<<std::endl;
    std::cout<<"this is the function "<<__FUNCTION__<<" and this is the c.number "<<c.number<<std::endl;
    std::cout<<"this is the numebr  "<<number<<std::endl;
}

//第五個友元的實現
//friend class percent<int>
template<typename T> class percent{
public:
    percent(T numbers):number(numbers){}
    void print(){
        task<int>a(10);
        task<double>b(20.4);
        task<char>c('h');
        std::cout<<"this is the function "<<__FUNCTION__<<" of the class of percent and this is the a.number "<<a.number<<std::endl;
        std::cout<<"this is the function "<<__FUNCTION__<<" of the class of percent and this is the b.number "<<b.number<<std::endl;
        std::cout<<"this is the function "<<__FUNCTION__<<" of the class of percent and this is the c.number "<<c.number<<std::endl;
    }
private:
    T number;
};

//第六個友元實現
//template<typename P> friend class frd;
template<typename P> class frd{
public:
    frd()=default;
    void print(){
        task<int>a(10);
        task<double>b(20.4);
        task<char>c('h');
        std::cout<<"this is the function "<<__FUNCTION__<<" of the class frd and this is the a.number "<<a.number<<std::endl;
        std::cout<<"this is the function "<<__FUNCTION__<<" of the class frd and this is the b.number "<<b.number<<std::endl;
        std::cout<<"this is the function "<<__FUNCTION__<<" of the class frd and this is the c.number "<<c.number<<std::endl;
    }
};
int main()
{ 
    task<int>a(10);
    task<double>b(20.4);
    task<char>c('h');
    //利用第一個友元函數
    next_time();
    std::cout<<std::endl;

    //利用第二個友元函數
    process(a);
    process(b);
    process(c);
    std::cout<<std::endl;

    //利用第三個友元函數來訪問task<T>
    preempt<int>(a);
    //preemt<int>(b);這樣的話是錯誤的,因爲你的b也就是task<double>類型的實例被初始化的時候,只聲明瞭
    //preempt<double>是其友元函數,所以你現在使用preempt<int>去訪問task<double>是不行的,因爲沒有聲明
    //preempt<int>是task<double>的友元函數
    preempt<double>(b);
    preempt<char>(c);
    std::cout<<std::endl;
    
    //利用第四個友元去訪問task<T>
    func<int>(10);
    std::cout<<std::endl;
    func<double>(20.5);
    std::cout<<std::endl;

    //第五個友元的使用
    percent<int> e(10);
    e.print();
    std::cout<<std::endl;
    /*
     * percent<double>f(20.4);//這樣做是錯誤的,因爲percent<int>被聲明成友元的,所以你只能是用percent<int>
     * f.print();//去訪問task<T>中的私有成員,但是不能使用percent<double>去訪問task<T>的私有成員
     */

    //第六種利用
    frd<int> g;
    frd<double> h;
    g.print();
    std::cout<<std::endl;
    h.print();
    return 0;
}

下面這個錯誤信息是第五個友元函數f去訪問的時候報的錯,其實就是沒有權限去訪問task類的私有成員,也就是f不是task的友元類的對象。

test_for_template.cpp: In instantiation of ‘void percent< <template-parameter-1-1> >::print() [with T = double]:
test_for_template.cpp:176:13:   required from here
test_for_template.cpp:81:7: error:int task<int>::number’ is private
     T number;
       ^
test_for_template.cpp:135:87: error: within this context
 <"this is the function "<<__FUNCTION__<<" and this is the a.number "<<a.number<
                                                                     ^
test_for_template.cpp:81:7: error:double task<double>::number’ is private
     T number;
       ^
test_for_template.cpp:136:87: error: within this context
 <"this is the function "<<__FUNCTION__<<" and this is the b.number "<<b.number<
                                                                     ^
test_for_template.cpp:81:7: error:char task<char>::number’ is private
     T number;
       ^
test_for_template.cpp:137:87: error: within this context
 <"this is the function "<<__FUNCTION__<<" and this is the c.number "<<c.number<
                                                                     ^

下面是程序的輸出:

this is the function next_time and this is the a.number 10
this is the function next_time and this is the b.number 20.4
this is the function next_time and this is the c.number h

this is the funcion process and this is the a.number 10
this is the funcion process and this is the a.number 20.4
this is the funcion process and this is the a.number h

this is the funcion preempt and this is the a.number 10
this is the funcion preempt and this is the a.number 20.4
this is the funcion preempt and this is the a.number h

this is the function func and this is the a.number 10
this is the function func and this is the b.number 20.4
this is the function func and this is the c.number h
this is the numebr  10

this is the function func and this is the a.number 10
this is the function func and this is the b.number 20.4
this is the function func and this is the c.number h
this is the numebr  20.5

this is the function print of the class of percent and this is the a.number 10
this is the function print of the class of percent and this is the b.number 20.4
this is the function print of the class of percent and this is the c.number h

this is the function print of the class frd and this is the a.number 10
this is the function print of the class frd and this is the b.number 20.4
this is the function print of the class frd and this is the c.number h

this is the function print of the class frd and this is the a.number 10
this is the function print of the class frd and this is the b.number 20.4
this is the function print of the class frd and this is the c.number h
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章