zoukankan      html  css  js  c++  java
  • 模板类的友元

    非模板友元

    声明一个常规友元

    template <class T>

    class HasFriend

    {

    public:

      friend void counts();

    }

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

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

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

    的静态数据成员。

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

    template<typename T>

    class HasFriend

    {

      friend void report(HasFriend<T> &);

    }

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

    void report(HasFriend<short> &){....}

    void report(HasFriend<int> &){...};

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

    #include<iostream>
    
    using std::cout;
    using std::cin;
    using std::endl;
    
    template<typename TT>
    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<TT> &);
    };
    
    template <typename T>
    int HasFriendT<T>::ct = 0;
    
    void counts()
    {
        cout<<"int count: "<<HasFriendT<int>::ct<<";";
        cout<<"double  count:"<<HasFriendT<double>::ct<<endl;
    }
    
    void report(HasFriendT<int> & hf)
    {
        cout<<hf.item<<endl;
    }
    
    void report(HasFriendT<double> & hf)
    {
        cout<<hf.item<<endl;
    }
    int main()
    {
        counts();
        HasFriendT<int> hfi1(10);
        counts();
        
        HasFriendT<double> hfdb(10.5);
        report(hfi1);
        HasFriendT<int> 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 <typename T>void counts()

    template <typename T> void report(T &);

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

    template <typename TT>

    class HasFriendT

    {

      friend void counts<TT>();

      friend void report<>(HasFriendT<TT> &);

    };

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

    HasFriendT<TT>

    然而也可以使用:

    report<HasFriendT<TT>>(HasFriendT<TT> &)

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

    TT是HasFriendT类的参数类型。

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

    假设声明了这样一个对象

    HasFriendT<int> squack;

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

    class HasFriendT<int>

    {

      friend void counts<int>();

      friend void report<>(HasFriendT<int> &);

    }

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

    看例子:

    #include<iostream>
    
    using std::cout;
    using std::cin;
    using std::endl;
    template <typename T> void counts();
    template <typename T> void report(T &);
    
    template<typename TT>
    class HasFriendT
    {
    private:
        TT item;
        static int ct;
    public:
        HasFriendT(const TT & i):item(i){ct++;};
        ~HasFriendT(){ct--;};
        friend void counts<TT>();
        friend void report<>(HasFriendT<TT> &);
    };
    
    template <typename T>
    int HasFriendT<T>::ct = 0;
    
    template<typename T>
    void counts()
    {
        cout<<"template size: "<<sizeof(HasFriendT<T>)<<";";
        cout<<"template counts():"<<HasFriendT<T>::ct<<endl;
    }
    template<typename T>
    void report(T & hf)
    {
        cout<<hf.item<<endl;
    }
    int main()
    {
        counts<int>();
        HasFriendT<int> hfi1(10);
        HasFriendT<int> hfi2(20);
        HasFriendT<double> hfdb(10.5);
        report(hfi1);
        report(hfi2);
        report(hfdb);
        cout<<"counts<int> output:
    ";
        counts<int>();
        cout<<"counts<double>() output:
    ";
        counts<double>();
        cin.get();
    }
    
    //template size: 4;template counts():0
    //10
    //20
    //10.5
    //counts<int> output:
    //template size: 4;template counts():2
    //counts<double>() output:
    //template size: 8;template counts():1

    counts<double> 和couts<int> 报告的模板大小不同,这样每种T类型都有自己的友元函数count();

    非约束模板友元

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

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

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

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

    template <typename T>

    {

      template <typename C,typename D>

      friend void Show2(C &,D &)

    }

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

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

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

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

    void Show2(ManyFirend<double> &,ManyFirend<int> &>(ManyFirend<double> & c,ManyFirend<int> & d);

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

    #include<iostream>
    using std::count;
    using std::cout;
    using std::endl;
    
    template<typename T>
    class ManyFriend
    {
    private:
        T item;
    public:
        ManyFriend(const T & i):item(i){};
        template<typename C,typename D>
        friend void Show2(C &,D &);
    };
    
    template<typename C,typename D>
    void Show2(C & c,D & d)
    {
        cout<<c.item<<","<<d.item<<endl;
    }
    
    int main()
    {
        ManyFriend<int> hfi1(10);
        ManyFriend<int> hfi2(20);
        ManyFriend<double> 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

     模板别名(c++ 11)

    如果能为类型指定别名,将很方便,在模板设计中尤其如此,可使用typedef 为模板具体化指定别名:

    typedef std::array<double,12> arrd;

    type std::array<int,12> arri;

    arrd gallons;//gallons 是 std::array<double,12> 类型

    arrai days;  //das 是std::array<int,12> 类型

    c++11新增了使用模板提供一系列的别名,如下

    template<typename T>

    using arratype = std::array<T,12>;

    这将arrtype定义为一个模板别名,可使用它来指定类型,如下所示:

    arratype<double> gallons;  // gallons是std::array<double,12>类型

    arratype<int> days;    //days 是 std::array<int ,12> 类型

    总之,arrtype<T>表示类型 std::array<T,12>.

    c++11 允许将语法using = 用于模板,用于非模板时,这种语法与常规typedef造价:

    typedef const char * pc1;//用pc1为const char *的别名

    using pc= const char * //用pc2为const char *的别名

    typedef int (*pfunc)(int);//

              //定义一个有10个指针的数组,该指针指向一个函数,该函数有一个整形参数,并返回一个整型?

              //第一种方法:int (*a[10])(int);

              //第二种方法:typedef int (*pfunc)(int);

              //用法    pfunc a[10];

     uisng pc1= const int *(*)[10]//  int *(*)[10]

     上边说的Remote方法可以影响Tv的对象,直接访问Tv的属性和方法。也可以通过让类彼此成为对方的友元来实现,

    即除了Remote是Tv的友元外,Tv还是Remote的友元。需要记住的一点是,对于使用Remote对象的Tv方法,其原型

    可在Remote类声明之前声明,但必须在Remote类声明之后定义,以便编译器有足够的信息来编译该方法。这种方案与

    下面类似 :

    class Tv

    {

      friend class Remote;

    public:

      void buzz(Remote & r);

    };

    class Remote

    {

      friend class Tv;

    public:

      void Bool volup(Tv & t){t.volup();};

    };

    inline void Tv::buzz(Remote & r)

    {

      ......

    };

    由于 Remote 的声明位于Tv声明后面,所以可以在类声明中定义Remote::volup(),但Tv::buzz()方法必须在Tv声明的外部定义,使

    其位于Remote声明的后面。如果不希望buzz()是内联的,则应在一个单独的方法定义文件中定义它。

    共同的友元:

    一个成员函数,它可以是一个类的成员,同时是另一个类的友元,但有时将函数作为两个类的友元更合理。例如,假定有一具Probe类和一个

    Analyzer类,前者表示某种可编程的测量设备,后者表示某种可编程的分析设备。这两个类都有内部时钟,且希望它们能够同步,则该包含下

    述代码行:

    class Analyzer;//前向声明

    前向声明使编译器看到Probe类声明中的友元声明时,知道Analyzer是一种类型。

    class Probe

    {

      friend void sync(Analyzer & a ,const Probe & p);

      friend void sync(Probe & p,const Analyzer & a);

    };

    class Analyzer

    {

      friend void sync(Analyzer & a ,const Probe & p);

      friend void sync(Probe & p,const Analyzer & a);

    };

    //定义这些友元函数

  • 相关阅读:
    ssi服务器端指令
    json格式的转换为json字符串函数
    接口测试基础和jmeter
    【JZOJ6274】梦境
    【JZOJ6275】小L的数列
    【luoguP4721】分治 FFT
    【luoguP3868】猜数字
    中国剩余定理与扩展中国剩余定理
    【JZOJ6277】矩阵游戏
    【JZOJ6271】锻造 (forging)
  • 原文地址:https://www.cnblogs.com/li-peng/p/3512887.html
Copyright © 2011-2022 走看看