有些情况下,允许特定的非成员函数访问一个类的私有成员,同时仍阻止一般的访问,这是很方便做到的。例如被重载的操作符,如输入或输出操作符,经常需要访问类的私有数据成员。

友元(frend)机制允许一个类将对其非公有成员的访问权授予指定的函数或者类,友元的声明以friend开始,它只能出现在类定义的内部,友元声明可以出现在类中的任何地方:友元不是授予友元关系的那个类的成员,所以它们不受其声明出现部分的访问控制影响。通常,将友元声明成组地放在类定义的开始或结尾是个好主意。

1、友元函数

友元函数是指某些虽然不是类成员函数却能够访问类的所有成员的函数。类授予它的友元特别的访问权,这样该友元函数就能访问到类中的所有成员。

#include <iostream>

using namespace std;

class A
{
public:
friend void set_show(int x, A &a); //该函数是友元函数的声明
private:
int data;
}; void set_show(int x, A &a) //友元函数定义,为了访问类A中的成员
{
a.data = x;
cout << a.data << endl;
}
int main(void)
{
class A a; set_show(, a); return ;
}

2、友元类

友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类中的隐藏信息(包括私有成员和保护成员)。当希望一个类可以存取另一个类的私有成员时,可以将该类声明为另一类的友元类。

关于友元类的注意事项:

(1) 友元关系不能被继承。
(2) 友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元,要看在类中是否有相应的声明。
(3) 友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元,同样要看类中是否有相应的申明。

#include <iostream>

using namespace std;

class A
{
public:
friend class C; //这是友元类的声明
private:
int data;
}; class C //友元类定义,为了访问类A中的成员
{
public:
void set_show(int x, A &a) { a.data = x; cout<<a.data<<endl;}
}; int main(void)
{
class A a;
class C c; c.set_show(, a); return ;
}

3、友元成员函数

使类B中的成员函数成为类A的友元函数,这样类B的该成员函数就可以访问类A的所有成员了。

当用到友元成员函数时,需注意友元声明和友元定义之间的相互依赖,在该例子中,类B必须先定义,否则类A就不能将一个B的函数指定为友元。然而,只有在定义了类A之后,才能定义类B的该成员函数。更一般的讲,必须先定义包含成员函数的类,才能将成员函数设为友元。另一方面,不必预先声明类和非成员函数来将它们设为友元。

#include <iostream>

using namespace std;

class A;    //当用到友元成员函数时,需注意友元声明与友元定义之间的互相依赖。这是类A的声明
class B
{
public:
void set_show(int x, A &a); //该函数是类A的友元函数
}; class A
{
public:
friend void B::set_show(int x, A &a); //该函数是友元成员函数的声明
private:
int data;
void show() { cout << data << endl; }
}; void B::set_show(int x, A &a) //只有在定义类A后才能定义该函数,毕竟,它被设为友元是为了访问类A的成员
{
a.data = x;
cout << a.data << endl;
} int main(void)
{
class A a;
class B b; b.set_show(, a); return ;
}

友元小结:

在需要允许某些特定的非成员函数访问一个类的私有成员(及受保护成员),而同时仍阻止一般的访问的情况下,友元是可用的。

优点:

可以灵活地实现需要访问若干类的私有或受保护的成员才能完成的任务;

便于与其他不支持类概念的语言(如C语言、汇编等)进行混合编程;

通过使用友元函数重载可以更自然地使用C++语言的IO流库。

缺点:

一个类将对其非公有成员的访问权限授予其他函数或者类,会破坏该类的封装性,降低该类的可靠性和可维护性。

参考资料:

1、《C++ Prime》第4版 第12章类的友元小节

http://blog.csdn.net/u012796139/article/details/46404401

友元(友元函数、友元类和友元成员函数) C++的更多相关文章

  1. C++类的成员函数(在类外定义成员函数、inline成员函数)

    类的成员函数(简称类函数)是函数的一种,它的用法和作用和前面介绍过的函数基本上是一样的,它也有返回值和函数类型,它与一般函数的区别只是:它是属于一个类的成员,出现在类体中.它可以被指定为private ...

  2. 类1(this指针/const成员函数/类作用域/外部成员函数/返回this对象的函数)

    假设我们要设计一个包含以下操作的 Sales_data 类: 1.一个 isbn 成员函数,用于返回对象的 book_no 成员变量 2.一个 combine 成员函数,用于将一个 Sales_dat ...

  3. CDocument类的UpdateAllViews()成员函数

    (一)UpdateAllViews() 与 Invalidate()的区别 UpdateAllViews()是在DOC/VIEW结构中,当一个视图的数据改变后,通知所有视图作相应的改变,和重画毫无关系 ...

  4. C++类的const成员函数、默认的构造函数、复制形参调用函数(转)

    C++类的const成员函数 double Sales_item::avg_price() const { } const关键字表明这是一个const成员函数,它不可以修改Sales_item类的成员 ...

  5. C++模板编程中只特化模板类的一个成员函数

    模板编程中如果要特化或偏特化(局部特化)一个类模板,需要特化该类模板的所有成员函数.类模板中大多数成员函数的功能可能是一模一样的,特化时我们可能只需要重新实现1.2个成员函数即可.在这种情况下,如果全 ...

  6. c++友元函数、友元类、友成员函数

    友元函数:不是类成员函数,是一个类外的函数,但是可以访问类所有成员. class Point{ public: friend void fun(Point t);//友元函数 private: int ...

  7. C++(十六) — 类中引用成员函数、命名空间的使用

    1.为什么类中引用成员函数? 类将属性和方法做了封装.类是一种数据类型,也就是:固定大小内存块的别名. 类的定义是一个抽象的概念,定义时不分配内存,当用类定义对象时,才分配一个固定大小的内存块. 此时 ...

  8. 为什么通过空指针(NULL)能够正确调用类的部分成员函数

    #include <iostream> using namespace std; class B { public: void foo() { cout << "B ...

  9. C++模板编程中只特化模板类的一个成员函数(花样特化一个成员函数)

    转自:https://www.cnblogs.com/zhoug2020/p/6581477.html 模板编程中如果要特化或偏特化(局部特化)一个类模板,需要特化该类模板的所有成员函数.类模板中大多 ...

  10. MFC 添加C++类,别的类不通过C++类的定义的对象就可以直接调用C++类里面的成员函数;

    MFC 添加C++类,不用定义C++类的对象,别的类不通过C++类的定义的对象就可以直接调用C++类里面的成员函数: 1先在mfc程序中添加普通类CProdata,然后删除头文件Prodata.h里面 ...

随机推荐

  1. Curator Recipes(Cache&Counter)

    Cache 路径缓存(Path Cache) 监视一个ZNode,当子节点增加.更新.删除改变状态时,路径缓存会在本地保存当前子节点及其数据和状态. public PathChildrenCache( ...

  2. 用Canvas,画中国国旗(Canvas基本知识点)

    .getContext("2d")=======>获取绘图接口 //2d .beginPath()========>创建绘图路径开始点 .moveTo(x,y)==== ...

  3. 学习AngularJs:Directive指令用法(完整版)

    这篇文章主要学习AngularJs:Directive指令用法,内容很全面,感兴趣的小伙伴们可以参考一下   本教程使用AngularJs版本:1.5.3 AngularJs GitHub: http ...

  4. python中的编码声明

    python中的第一行,目的就是指出,你想要你的这个文件中的代码用什么可执行程序去运行它,就这么简单 #!/usr/bin/python 相当于写死了 python 路径(是告诉OS执行这个py时,调 ...

  5. JavaEE XML DOM解析

    DOM解析XML @author ixenos XML解析方式(原理) a)     DOM 解析树 b)     SAX  流事件 DOM解析对应主流工具 i.          DOM(官方) i ...

  6. C#中的重写和覆盖的区别

    #中重写(override)和覆盖(new)的区别 重写用关键字 virtual 修饰的方法,叫虚方法.可以在子类中用override 声明同名的方法,这叫“重写”.相应的没有用virtual修饰的方 ...

  7. C#中的系统时间获取问题

    C#获取当前系统时间 2010-01-02 16:24 --DateTime 数字型 System.DateTime currentTime=new System.DateTime(); 取当前年月日 ...

  8. Webupload + MVC 之上传下载

    最近工作中用到了 MVC 的上传及下载 , 写下感受 本项目中用到的是百度的webuploader <!--引入Jquery--> <script src="~/Conte ...

  9. CentOS7 下安装telnet服务

    今天搞了下 Centos 7 下面升级 openssl 和 openssh ,顺便装了下 telnet # 安装 telnet 避免 ssh 无法登录 yum -y install xinetd te ...

  10. kali客户端攻击

    浏览器攻击 browser_autpwn2 (BAP2) mkdir /test 为接受响应的服务器创建目录   use auxiliary/server/browser_autopwn2  set ...