应用:
PG1.m_VecPt == PG2.m_VecPt (1)
PG1是nestPolygon类的对象,m_VecPt是nestPolygon类的成员变量,定义如下:
vector<nestPoint2D> m_VecPt; 因为nestPoint2D不是内建类型,所以不能直接使用==等号,所以需要重载==。
class AFX_EXT_CLASS nestPoint2D
{
Friend bool operator==(const nestPoint2D& npt1, const nestPoint2D& npt2);
}
展开:
1、整个类可以是另一个类的友元,该友元也可以称做为友类。
class Internet;
class Country
{
friend class Internet;//友类的声明,形象的说:Internet是Country的朋友
};
这样Internet类中的成员函数可以通过函数参数(也就是Country对象或者Country对象引用)访问Country类的私有成员。
(理解:Country声明 Internet是是它的友元(朋友),那么 Country就信任Internet,所以在Internet中的成员函数,通过Country对象或者Country对象引用就能够访问Internet的私有数据)
在迭代器中也有类似的用法:(实质上这个是嵌套友元类的用法,同时这也是一种设计模式)
Template<class T, int ssize = 100>
Class StackTemplate
{
T stack[ssize];//private
Int top;
StackTemplate():top(0){} //constructor
Class iterator;//forward declaration
Friend class iterator; //让iterator类成为StackTemplate的友元类
Class iterator //定义一个类
{
StackTemplate& s;
Int index
iterator (StackTemplate& st): s(st),index(0){}
iterator (StackTemplate& st, bool):s(st),index(s.top){}
T operator*() const { return s.stack[index];}
//这里operator*()访问了StackTemplate类是私有成员
//重载++,+ 等运算符
}
iterator begin() { return iterator(*this) }
iterator end() { return iterator(*this, bool) }
}
使用:
StackTemplate<int> is;
StackTemplate<int>::iterator iterStart = is.begin();
StackTemplate<int>::iterator iterEnd = is.end();
2、一个类的成员函数可以是另一个类的友元
class Internet;
class Country
{
void Editurl(Internet &temp);//成员函数的声明
};
class Internet
{
friend void Country::Editurl(Internet &temp);//友元函数的声明
};
通过友元函数的参数Internet对象,访问Internet类的私有成员。
(理解:在Internet中 申明Country的成员函数Editurl是Internet的友元函数,那么Internet 信任该函数,所以函数Country::Editurl可以通过Internet对象访问Internet的私有成员)
3、一个普通函数可以是(多个)类的友元函数。这类普通函数的参数都有类的对象,从而通过该对象,操作该类的私有成员,该函数被当作全局函数。
4、二元中缀运算符,如果第一个运算数不是类对象,通常把该函数声明为该类的友元函数。另外:在ostream的重载<<或者>>符号的时候,通常声明为友元函数。
5、友元关系既不继承,也不传递
- 我不见得信任我朋友的孩子。友元的特权不被继承。友元的派生类不一定是友元。如果 Fred 类声明Base类是友元,那么Base类的派生类不会自动地被赋予对于Fred的对象的访问特权。
- 我不见得信任我朋友的朋友。友元的特权不被传递。友元的友元不一定是友元。如果Fred类声明Wilma类是友元,并且Wilma类声明Betty类是友元,那么Betty类不会自动地被赋予对于Fred的对象的访问特权。
- 你不见得仅仅因为我声称你是我的朋友就信任我。友元的特权不是自反的。如果Fred类声明Wilma类是友元,则Wilma对象拥有访问Fred对象的特权,但Fred对象不会自动地拥有对Wilma对象的访问特权。
6、友元函数主要缺点是需要额外的代码来支持动态绑定。
要得到虚友元(virtual friend)的效果,友元函数应该调用一个隐藏的(通常是 protected:)虚成员函数。
class Base {
public:
friend void f(Base& b);
// ...
protected:
virtual void do_f();
// ...
};
inline void f(Base& b)
{
b.do_f();
}
class Derived : public Base {
public:
// ...
protected:
virtual void do_f(); // "覆盖" f(Base& b)的行为
// ...
};
void userCode(Base& b)
{
f(b);
}
在userCode(Base&)中的f(b)语句将调用虚拟的 b.do_f()。这意味着如果b实际是一个派生类的对象,那么Derived::do_f()将获得控制权。注意派生类覆盖的是保护的虚(protected: virtual)成员函数 do_f(); 而不是它友元函数f(Base&)。
一个使用虚友元函数用法更实际的例子:(为一个完整的继承层次的类提供打印)
class Base {
public:
friend std::ostream& operator<< (std::ostream& o, const Base& b);
// ...
protected:
virtual void printOn(std::ostream& o) const;
};
inline std::ostream& operator<< (std::ostream& o, const Base& b)
{
b.printOn(o);
return o;
}
class Derived : public Base {
protected:
virtual void printOn(std::ostream& o) const;
};