模板类的友元

非模板友元

声明一个常规友元

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:\n";
    counts<int>();
    cout<<"counts<double>() output:\n";
    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);

};

 

//定义这些友元函数

时间: 2024-10-14 22:20:04

模板类的友元的相关文章

C++中模板类使用友元模板函数

在类模板中可以出现三种友元声明:(1)普通非模板类或函数的友元声明,将友元关系授予明确指定的类或函数.(2)类模板或函数模板的友元声明,授予对友元所有实例的访问权.(3)只授予对类模板或函数模板的特定实例的访问权的友元声明. (1)普通友元: template<class T> class A{    friend void fun(); //... };此例中fun可访问A任意类实例中的私有和保护成员 (2)一般模板友元关系 template<class type> class

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

问题描述 C++怎么把模板类设置为友元? 求好心人解答~~ 1.怎么把模板类设置为友元??模板函数 模板类. 2.设置的时候 需要具体化吗?? 是不是 可以具体化 也可以不具体?? 解决方案 参考:http://www.cnblogs.com/li-peng/p/3512887.html 解决方案二: 根据<C++ Primer>第三版16.4节的叙述,C++类模板友元分为以下几种情况 1.非模板友元类或友元函数. 书上给了一个例子: class Foo{ void bar(); }; tem

C++第7周(春)项目5 复数模板类(加使用友元函数拓展)

课程首页在:http://blog.csdn.net/sxhelijian/article/details/11890759,内有完整教学方案及资源链接 [项目5-复数模板类] 阅读P314的例10.1.该例实现了一个复数类,但是美中不足的是,复数类的实部和虚部都固定只能是double型的.可以通过模板类的技术手段,设计Complex,使实部和虚部的类型为定义对象时用的实际类型. (1)要求类成员函数在类外定义. (2)在此基础上,再实现减法.乘法和除法 你可以使用的main()函数如下: in

【C/C++学院】0825-类模板/final_override/类模板与普通类的派生类模板虚函数抽象模板类/类模板友元/位运算算法以及类声明/Rtti 实时类型检测/高级new创建/类以及函数包装器

类模板 类模板多个类型默认类型简单数组模板 #pragma once template <class T=int>//类模板可以有一个默认的值 class myArray { public: myArray(); ~myArray(); }; #include "myArray.h" template <class T=int>//每一个函数都需要加上一个默认的值 myArray<T>::myArray() //类模板成员函数在外部,需要加载类型初始

C++第7周项目5 - 模板类中使用友元函数

课程首页地址:http://blog.csdn.net/sxhelijian/article/details/7910565,本周题目链接:http://blog.csdn.net/sxhelijian/article/details/8775137 [项目5-模板类中使用友元函数]友元函数提供了一种非成员函数访问私有数据成员的途径,模板类使类中的数据成员的类型变得灵活,这两种技术可以结合起来用.要求在项目4的基础上能够支持用友员函数实现的加法.用于测试的main()函数如下: int main

C++中类模板(class template)友元(friend) 的全部六种形式

类模板(class template)的友元(friend)和普通类的友元, 有很多区别, 主要原因是类模板包含模板参数(template parameter), 就会导致友元和类模板有很多匹配形式; 主要包含六种形式: 1. 类 - 友元(friend): "模板参数是当前类"的类模板; 2. 类 - 友元: "模板参数任意"的模板类; 3. 模板类 - 友元: "模板参数相同"的模板类; 4. 模板类 - 友元: "模板参数任意&q

【C/C++学院】(11)泛型编程/函数模板/类模板

1.泛型编程基础 #include "iostream" using namespace std; void swap(int &a, int &b) { int c; c = a; a = b; b = c; } void swap(float &a, float &b) { float c; c = a; a = b; b = c; } void main() { int a = 1, b = 2; swap(a, b); float a1 = 1,

c++学习笔记之类模板中的友元声明

类模板中出现3种友元声明,每一种友元声明了与一个或者多个实体的友元关系 (1)普通非模板类或函数的友元声明,将友元关系授予明确指定的类或函数. (2)类模板或函数模板的友元声明,授予对友元所有实例的访问权. (3)只授予对类模板或函数模板的特定实例的访问权的友元声明. 1 普通友元 非模板类或非模板函数可以是类模板的友元. #include <iostream> using namespace std; template <class Type> class Bar{ //普通非模

第7周-任务3-复数模板类

[预备]阅读P314的例10.1. #include <iostream> using namespace std; class Complex { public: Complex( ){real=0;imag=0;} Complex(double r,double i){real=r;imag=i;} Complex complex_add(Complex &c2); void display( ); private: double real; double imag; }; Com