开发者社区> 问答> 正文

C++怎么把模板类设置为友元?

求好心人解答~~
1.怎么把模板类设置为友元??模板函数 模板类。
2.设置的时候 需要具体化吗?? 是不是 可以具体化 也可以不具体??
同问0 |浏览435| 收藏0 |分享

展开
收起
a123456678 2016-03-05 15:07:59 2174 0
3 条回答
写回答
取消 提交回答
  • 乐于学习与分析

    非模板友元

    声明一个常规友元

    template

    class HasFriend

    {

    public:

      friend void counts();

    }

    上边的声明使counts()函数成为模板所有实例化的友元

    counts()函数不是通过对象调用的(它是友元,不是成员函数),也没有对象参数,那么它如何访问HasFriend对象的呢

    有很多种可能性。它可以访问全局对象;可以使用全局指针访问非全局对象;可以创建自己的对象;可以访问独立对象的模板类

    的静态数据成员。

    如果要为友元函数提供械板类参数,可以如下所示来进行友元声明。要提供模板类参数,必须指明基体化

    template

    class HasFriend

    {

      friend void report(HasFriend &);

    }

    report()本身并不是模板函数,而只是使用一个模板作参数。这意味着必须要使用的友元定义显式基体化:

    void report(HasFriend &){....}

    void report(HasFriend &){...};

    也就是说report(HasFriend &)将成为HasFriend类的友元。

    复制代码

    include
    using std::cout;
    using std::cin;
    using std::endl;

    template
    class HasFriendT
    {
    private:

    TT item;
    static int ct;
    public:

    HasFriendT(const TT & i):item(i){ct++;};
    ~HasFriendT(){ct--;};
    friend void counts();
    friend void report(HasFriendT &);
    };

    template
    int HasFriendT::ct = 0;

    void counts()
    {

    cout<<"int count: "<::ct<<";";
    cout<<"double count:"<::ct<}

    void report(HasFriendT & hf)
    {

    cout<}

    void report(HasFriendT & hf)
    {

    cout<}
    int main()
    {

    counts();
    HasFriendT hfi1(10);
    counts();

    HasFriendT hfdb(10.5);
    report(hfi1);
    HasFriendT hfi2(20);

    report(hfi2);
    report(hfdb);

    counts();
    cin.get();
    }

    //int count: 0;double count:0
    //int count: 1;double count:0
    //10
    //20
    //10.5
    //int count: 2;double count:1
    复制代码

    约束模板友元函数友元的类型取决于类被实例化时的类型

    可以修改上边的示例,使友元函数本身成为模板。具体的说,为约束模板友元作准备,要使类的每一个基体

    化都获得与友元匹配的基体化。这需要3部

    1首先,在类定义的前面声明每个模板函数

    template void counts()

    template void report(T &);

    2然后,在函数中再次将模板声明为友元。这些语句根据类模板参数的类型声明具体化:

    template

    class HasFriendT

    {

      friend void counts();

      friend void report<>(HasFriendT &);

    };

    声明中的<>指出这是模板具体化。对于report(),<>可以为空,因为可以从函数参数推断出如下模板类型参数:

    HasFriendT

    然而也可以使用:

    report>(HasFriendT &)

    但是counts()函数没有参数,因此必须使用模板参数语法()来指明其基体化。还需要注意的是,

    TT是HasFriendT类的参数类型。

      同样,理解这些声明的最佳方式也是设想声明一个特定具体化的对象时,它们将变成什么样子。例如,

    假设声明了这样一个对象

    HasFriendT squack;

    编译器将用int替换TT,并生成下面的类定义

    class HasFriendT

    {

      friend void counts();

      friend void report<>(HasFriendT &);

    }

    3第三个条件是为友元提供模板定义

    看例子:

    复制代码

    include
    using std::cout;
    using std::cin;
    using std::endl;
    template void counts();
    template void report(T &);

    template
    class HasFriendT
    {
    private:

    TT item;
    static int ct;
    public:

    HasFriendT(const TT & i):item(i){ct++;};
    ~HasFriendT(){ct--;};
    friend void counts();
    friend void report<>(HasFriendT &);
    };

    template
    int HasFriendT::ct = 0;

    template
    void counts()
    {

    cout<<"template size: "<)<<";";
    cout<<"template counts():"<::ct<}
    template
    void report(T & hf)
    {

    cout<}
    int main()
    {

    counts();
    HasFriendT hfi1(10);
    HasFriendT hfi2(20);
    HasFriendT hfdb(10.5);
    report(hfi1);
    report(hfi2);
    report(hfdb);
    cout<<"counts output:n";
    counts();
    cout<<"counts() output:n";
    counts();
    cin.get();
    }

    //template size: 4;template counts():0
    //10
    //20
    //10.5
    //counts output:
    //template size: 4;template counts():2
    //counts() output:
    //template size: 8;template counts():1
    复制代码
    counts 和couts 报告的模板大小不同,这样每种T类型都有自己的友元函数count();

    非约束模板友元

    友元的所有具体化都是类的每一个具体化的友元

    上边说的约束模板友元函数是在类外面声明的模板的具体化。int类型具体化获得int函数具体化,

    依此类推。通过在类内部声明模板,可以创建非约束友元函数,即每个函数具体化都是每个类具体化的友元。

    对于非约束友元,友元模板类型参数与模板类类型参数是不同的:

    template

    {

      template

      friend void Show2(C &,D &)

    }

    上边是一个使用非约束友元函数的例子,其中,函数调用show2(hfi1,hfi2)与下面的具体化匹配:

    void Show2 &,ManyFriend &>(ManyFriend & c,ManyFriend & d);

    因为它是所有ManyFriend 具体化的友元,所以能够访问所有具体化的item成员,但它只访问了ManyFriend对象。

    同样Show2(hfd,hfd2)与下面具体化匹配:

    void Show2(ManyFirend &,ManyFirend &>(ManyFirend & c,ManyFirend & d);

    它也是所有ManyFriend具体化的友元,并访问了ManyFirend 对象的item成员和ManyFriend对象的item成员

    复制代码

    include
    using std::count;
    using std::cout;
    using std::endl;

    template
    class ManyFriend
    {
    private:

    T item;
    public:

    ManyFriend(const T & i):item(i){};
    template
    friend void Show2(C &,D &);
    };

    template
    void Show2(C & c,D & d)
    {

    cout<}

    int main()
    {

    ManyFriend hfi1(10);
    ManyFriend hfi2(20);
    ManyFriend hfdb(10.5);

    cout<<"hfi1, hfi2";
    Show2(hfi1,hfi2);
    cout<<"hfdb,hfi2: ";

    Show2(hfdb,hfi2);
    std::cin.get();
    }

    //hfi1, hfi210,20
    //hfdb,hfi2: 10.5,20

    2019-07-17 18:53:33
    赞同 展开评论 打赏
  • 软件开发,安全加密

    非模板友元

    声明一个常规友元

    template

    class HasFriend

    {

    public:

      friend void counts();

    }

    上边的声明使counts()函数成为模板所有实例化的友元

    counts()函数不是通过对象调用的(它是友元,不是成员函数),也没有对象参数,那么它如何访问HasFriend对象的呢

    有很多种可能性。它可以访问全局对象;可以使用全局指针访问非全局对象;可以创建自己的对象;可以访问独立对象的模板类

    的静态数据成员。

    如果要为友元函数提供械板类参数,可以如下所示来进行友元声明。要提供模板类参数,必须指明基体化

    template

    class HasFriend

    {

      friend void report(HasFriend &);

    }

    report()本身并不是模板函数,而只是使用一个模板作参数。这意味着必须要使用的友元定义显式基体化:

    void report(HasFriend &){....}

    void report(HasFriend &){...};

    也就是说report(HasFriend &)将成为HasFriend类的友元。

    复制代码

    include
    using std::cout;
    using std::cin;
    using std::endl;

    template
    class HasFriendT
    {
    private:

    TT item;
    static int ct;
    public:

    HasFriendT(const TT & i):item(i){ct++;};
    ~HasFriendT(){ct--;};
    friend void counts();
    friend void report(HasFriendT &);
    };

    template
    int HasFriendT::ct = 0;

    void counts()
    {

    cout<<"int count: "<::ct<<";";
    cout<<"double count:"<::ct<}

    void report(HasFriendT & hf)
    {

    cout<}

    void report(HasFriendT & hf)
    {

    cout<}
    int main()
    {

    counts();
    HasFriendT hfi1(10);
    counts();

    HasFriendT hfdb(10.5);
    report(hfi1);
    HasFriendT hfi2(20);

    report(hfi2);
    report(hfdb);

    counts();
    cin.get();
    }

    //int count: 0;double count:0
    //int count: 1;double count:0
    //10
    //20
    //10.5
    //int count: 2;double count:1
    复制代码

    约束模板友元函数友元的类型取决于类被实例化时的类型

    可以修改上边的示例,使友元函数本身成为模板。具体的说,为约束模板友元作准备,要使类的每一个基体

    化都获得与友元匹配的基体化。这需要3部

    1首先,在类定义的前面声明每个模板函数

    template void counts()

    template void report(T &);

    2然后,在函数中再次将模板声明为友元。这些语句根据类模板参数的类型声明具体化:

    template

    class HasFriendT

    {

      friend void counts();

      friend void report<>(HasFriendT &);

    };

    声明中的<>指出这是模板具体化。对于report(),<>可以为空,因为可以从函数参数推断出如下模板类型参数:

    HasFriendT

    然而也可以使用:

    report>(HasFriendT &)

    但是counts()函数没有参数,因此必须使用模板参数语法()来指明其基体化。还需要注意的是,

    TT是HasFriendT类的参数类型。

      同样,理解这些声明的最佳方式也是设想声明一个特定具体化的对象时,它们将变成什么样子。例如,

    假设声明了这样一个对象

    HasFriendT squack;

    编译器将用int替换TT,并生成下面的类定义

    class HasFriendT

    {

      friend void counts();

      friend void report<>(HasFriendT &);

    }

    3第三个条件是为友元提供模板定义

    看例子:

    复制代码

    include
    using std::cout;
    using std::cin;
    using std::endl;
    template void counts();
    template void report(T &);

    template
    class HasFriendT
    {
    private:

    TT item;
    static int ct;
    public:

    HasFriendT(const TT & i):item(i){ct++;};
    ~HasFriendT(){ct--;};
    friend void counts();
    friend void report<>(HasFriendT &);
    };

    template
    int HasFriendT::ct = 0;

    template
    void counts()
    {

    cout<<"template size: "<)<<";";
    cout<<"template counts():"<::ct<}
    template
    void report(T & hf)
    {

    cout<}
    int main()
    {

    counts();
    HasFriendT hfi1(10);
    HasFriendT hfi2(20);
    HasFriendT hfdb(10.5);
    report(hfi1);
    report(hfi2);
    report(hfdb);
    cout<<"counts output:n";
    counts();
    cout<<"counts() output:n";
    counts();
    cin.get();
    }

    //template size: 4;template counts():0
    //10
    //20
    //10.5
    //counts output:
    //template size: 4;template counts():2
    //counts() output:
    //template size: 8;template counts():1
    复制代码
    counts 和couts 报告的模板大小不同,这样每种T类型都有自己的友元函数count();

    非约束模板友元

    友元的所有具体化都是类的每一个具体化的友元

    上边说的约束模板友元函数是在类外面声明的模板的具体化。int类型具体化获得int函数具体化,

    依此类推。通过在类内部声明模板,可以创建非约束友元函数,即每个函数具体化都是每个类具体化的友元。

    对于非约束友元,友元模板类型参数与模板类类型参数是不同的:

    template

    {

      template

      friend void Show2(C &,D &)

    }

    上边是一个使用非约束友元函数的例子,其中,函数调用show2(hfi1,hfi2)与下面的具体化匹配:

    void Show2 &,ManyFriend &>(ManyFriend & c,ManyFriend & d);

    因为它是所有ManyFriend 具体化的友元,所以能够访问所有具体化的item成员,但它只访问了ManyFriend对象。

    同样Show2(hfd,hfd2)与下面具体化匹配:

    void Show2(ManyFirend &,ManyFirend &>(ManyFirend & c,ManyFirend & d);

    它也是所有ManyFriend具体化的友元,并访问了ManyFirend 对象的item成员和ManyFriend对象的item成员

    复制代码

    include
    using std::count;
    using std::cout;
    using std::endl;

    template
    class ManyFriend
    {
    private:

    T item;
    public:

    ManyFriend(const T & i):item(i){};
    template
    friend void Show2(C &,D &);
    };

    template
    void Show2(C & c,D & d)
    {

    cout<}

    int main()
    {

    ManyFriend hfi1(10);
    ManyFriend hfi2(20);
    ManyFriend hfdb(10.5);

    cout<<"hfi1, hfi2";
    Show2(hfi1,hfi2);
    cout<<"hfdb,hfi2: ";

    Show2(hfdb,hfi2);
    std::cin.get();
    }

    //hfi1, hfi210,20
    //hfdb,hfi2: 10.5,20

    2019-07-17 18:53:33
    赞同 展开评论 打赏
  • 根据《C++ Primer》第三版16.4节的叙述,C++类模板友元分为以下几种情况
    1.非模板友元类或友元函数。 书上给了一个例子:
    class Foo{
    void bar();
    };
    template
    class QueueItem{
    friend class foobar;
    friend void foo();
    friend void Foo::bar();
    //....
    };
    很简单,跟非模板类没什么区别,有一点需要注意,如果要把函数和类生命为友元,前面不需要声明或定义。但是如果要把类成员函数声明为友元,则前面必须有类的定义(注意不是声明,是定义),因为一个类成员只能由该类的定义引入 。

    2.绑定的友元类模板或函数模板。 例子如下:
    template
    class foobar{ ...};

    template
    void foo(QueueItem);

    template
    class Queue{
    void bar();
    //...
    };

    template
    class QueueItem {
    friend class foobar ;
    friend void foo (QueueItem);
    friend void Queue ::bar();
    //...
    };
    需要注意两点:
    a.与非模板函数或类不同,模板函数或类声明为友元之前必须在前面声明过 ,否则无法通过编译。
    b.注意红字部分,那几个Type不能少。比如对于函数foo,如果少了的话编译器会将其作为非模板函数对待,也就是说,对于QueueItem,编译器会查找void foo(QueueItem),而对templatevoid foo(QueueItem)视而不见,如果没找到非模板函数则会报错。

    3.非绑定友元类模板或函数模板。 举例如下:
    template
    class QueueItem {
    template
    friend class foobar;

    template

    friend void foo(QueueItem<T>);
    

    template

    friend void Queue<T>::bar();

    //...
    };

    2019-07-17 18:53:33
    赞同 展开评论 打赏
问答分类:
C++
问答地址:
问答排行榜
最热
最新

相关电子书

更多
使用C++11开发PHP7扩展 立即下载
GPON Class C++ SFP O;T Transce 立即下载
GPON Class C++ SFP OLT Transce 立即下载