1.什么是友元
在一个类A中,将类B声明为友元类,则类B可以访问类A的私有成员和保护成员。另外,也可以将函数声明为友元函数。

2.什么时候用到友元
若不同的类之间某些共享数据成员,可以使用友元,简化类的设计。

3.友元类
友元类的声明:friend class 类名
示例如下:
对于电视和遥控器来说,都共享频道数据成员和开关操作,这时可以将遥控器声明为电视的友元类,则遥控器可以直接访问电视的数据成员,且一个遥控器可以控制多台电视,这则例子很好的体现了友元的特点。

tv.h

#ifndef TV_H_
#define TV_H_
class Tv
{
public :
friend class Remote;
enum State{off,on}; Tv(int s=off,int mc=):state(s),maxchannel(mc),channel(){} void onoff(){state=(state==on)?off:on;}
void chanup();
void chandown();
void settings() const;
private:
int state;
int maxchannel;
int channel;
};
class Remote{
public:
Remote(){};
void onoff(Tv &t){t.onoff();};
void chanup(Tv &t){t.chanup();};
void chandown(Tv &t){t.chandown();};
void set_chan(Tv &t,int c){t.channel=c;};
};

tv.cpp

#include<iostream>
#include "tv.h"
void Tv::chanup()
{
if(channel<maxchannel){
channel++;
}
else{
channel = ;
}
}
void Tv::chandown()
{
if(channel>){
channel--;
}
else{
channel = maxchannel;
}
}
void Tv::settings() const
{
using std::cout;
using std::endl;
cout<<"Tv is "<<(state==on?"on":"off")<<endl;
if(state==on)
{
cout<<"channel:"<<channel<<endl;
}
}

use_tv.cpp 可使用同一个遥控器控制多台不同的电视

#include<iostream>
#include "tv.h"
int main()
{
using std::cout;
using std::endl;
Tv s42;
cout<<"Initing Tv s42......"<<endl;
s42.settings();
s42.onoff();
s42.chanup();
cout<<"adjusted Tv s42....."<<endl;
s42.settings(); Remote control;
control.set_chan(s42,);
control.volup(s42);
cout<<"settings after using remote......"<<endl;
s42.settings();
getchar();
return ;
}

示例可以看出,若不使用友元,则必须将Tv类的私有部分设置为共有的,或者创建一个大型类来包含电视和遥控器。这种解决方法也无法反应,一个遥控器可以用于多台电视。

4.友元函数
从上例可以看出,Remote类只有set_chan方法使用到了Tv类的私有成员,因此我们可以让Remote::set_chan()成为Tv类的友元函数,而不必让整个类成为友元。

tvfm.h

#ifndef TV_H_
#define TV_H_
class Tv;
class Remote{
public :
enum State{off,on};
private:
int mode;
public:
Remote(){};
void onoff(Tv &t);
void chanup(Tv &t);
void chandown(Tv &t);
void set_chan(Tv &t,int c);
};
class Tv
{
public :
friend void Remote::set_chan(Tv &t,int c);
enum State{off,on}; Tv(int s=off,int mc=):state(s),maxchannel(mc),channel(){} void onoff(){state=(state==on)?off:on;}
void chanup();
void chandown();
void settings() const;
private:
int state;
int maxchannel;
int channel;
}; inline void Remote::onoff(Tv &t){t.onoff();}
inline void Remote::chanup(Tv &t){t.chanup();}
inline void Remote::chandown(Tv &t){t.chandown();}
inline void Remote::set_chan(Tv &t,int c){t.channel=c;}
#endif

5.共同的友元
多个类需要访问同一个函数,则可以在这些类中将这个函数声明为友元函数。例如:有一个计数器函数counter,两个类A和B同时调用这个函数,则可以在类A和B中将函数counter声明为友元函数。

void counter()
{
//....
}
class A
{
friend int counter();
}
class B
{
friend int counter();
}

6.使用友元类时注意:
1) 友元关系不能被继承。
2)友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元。
3) 友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元

参考资料:《C++ Primer.Plus》 pp.602-610

C++友元详解的更多相关文章

  1. 14.C++-二阶构造模式、友元(详解)

    首先回顾以前所学的构造函数 类的构造函数用于对象的初始化 构造函数与类同名并且没有返回值 构造函数在定义时被自动调用 由于构造函数没有返回值不能判断执行结果,所以不能保证初始化对象能否成功 比如: c ...

  2. C++中友元详解

    问题的提出 我们已知道类具备封装和信息隐 藏的特性.只有类的成员函数才能访问类的私有成员,程式中的其他函数是无法访问私有成员的.非成员函数能够访问类中的公有成员,但是假如将数据成员都定义 为公有的,这 ...

  3. 《挑战30天C++入门极限》入门教程:实例详解C++友元

        入门教程:实例详解C++友元 在说明什么是友元之前,我们先说明一下为什么需要友元与友元的缺点: 通常对于普通函数来说,要访问类的保护成员是不可能的,如果想这么做那么必须把类的成员都生命成为pu ...

  4. C++ Namespace 详解

    命名空间的定义格式为:(取自C++标准文档) named-namespace-definition: namespace identifier { namespace-body } unnamed-n ...

  5. C++:虚函数的详解

    5.4.2 虚函数详解 1.虚函数的定义 虚函数就是在基类中被关键字virtual说明,并在派生类重新定义的函数.虚函数的作用是允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问 ...

  6. STL priority_queue 常见用法详解

    <算法笔记>学习笔记 priority_queue 常见用法详解 //priority_queue又称优先队列,其底层时用堆来实现的. //在优先队列中,队首元素一定是当前队列中优先级最高 ...

  7. Linq之旅:Linq入门详解(Linq to Objects)

    示例代码下载:Linq之旅:Linq入门详解(Linq to Objects) 本博文详细介绍 .NET 3.5 中引入的重要功能:Language Integrated Query(LINQ,语言集 ...

  8. 架构设计:远程调用服务架构设计及zookeeper技术详解(下篇)

    一.下篇开头的废话 终于开写下篇了,这也是我写远程调用框架的第三篇文章,前两篇都被博客园作为[编辑推荐]的文章,很兴奋哦,嘿嘿~~~~,本人是个很臭美的人,一定得要截图为证: 今天是2014年的第一天 ...

  9. EntityFramework Core 1.1 Add、Attach、Update、Remove方法如何高效使用详解

    前言 我比较喜欢安静,大概和我喜欢研究和琢磨技术原因相关吧,刚好到了元旦节,这几天可以好好学习下EF Core,同时在项目当中用到EF Core,借此机会给予比较深入的理解,这里我们只讲解和EF 6. ...

随机推荐

  1. 解决java.lang.OutOfMemoryError: unable to create new native thread问题

    解决:1.升级JVM到最新的版本 最新版本的JVM一般在内存优化方面做的更好,升级JVM到最新的版本可能会缓解测问题2.从操作系统层面去解决 使用64位操作系统 如果使用32位操作系统遇到unable ...

  2. 全国出现大面积DNS服务器故障 域名被劫持

    1月21日消息,继今日上午腾讯16项服务出现故障后,大量网站出现了无法访问的情况,据了解,该故障是由于国内DNS根服务器故障所致. 据了解,此次攻击式由于国内所有通用顶级域的根服务器出现异常,导致大量 ...

  3. 【Java虚拟机】运行时数据区

    Java在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途.创建和销毁的时间,有一些是随虚拟机的启动而创建,随虚拟机的退出而销毁,有些则是与线程一一对应,随 ...

  4. 获取泛型类对应的class类型

    自己写来备忘的,如有错误,请指正! public class Demo<T> { private Class<T> clazz; public Demo() { Paramet ...

  5. (转)J2EE十三个技术规范

    从事Java开发的童鞋都知道,java是一种非常棒的语言,能够实现跨平台运行.它屏蔽了具体的平台环境的要求,也就是说,无论是windows,还是Unix.Linux系统,只要支持Java虚拟机,就可以 ...

  6. oracle默认连接数150

    当oracle连接数超过最大的150登录不上 sqlplus / as sysdba   ###报错,提示连接数未释放! ---释放网络连接数 ps -ef |grep ora |grep " ...

  7. (四)Linux Shell编程——输入输出重定向

    Unix 命令默认从标准输入设备(stdin)获取输入,将结果输出到标准输出设备(stdout)显示.一般情况下,标准输入设备就是键盘,标准输出设备就是终端,即显示器. 1. 输出重定向 命令的输出不 ...

  8. 用UNetbootin轻松把Linux操作系统装进U盘

    转自http://www.hackbase.com/tech/2009-02-14/51197.html1.下载Linux发行版的iso镜像.    如Hiweed GNU/Linux:http:// ...

  9. java多线程(五)之总结(转)

    引 如果对什么是线程.什么是进程仍存有疑惑,请先Google之,因为这两个概念不在本文的范围之内. 用多线程只有一个目的,那就是更好的利用cpu的资源,因为所有的多线程代码都可以用单线程来实现.说这个 ...

  10. java导出文件IE/Google文件名乱码兼容

      导出文件名乱码解决方案: String agent = request.getHeader("User-Agent"); boolean isMSIE = (agent != ...