写这篇文章的动机来源于网友purewinter在我的那篇《重读《设计模式》之学习笔记(三)--SINGLETON模式的疑惑》中的评论。
    在那篇文章中,我提供了如下一个用C++实现的Singletion模式的小例子:

class  ClxSingletonMEC
{
public :
    friend ClxSingletonMEC &  InstanceMEC();

private :
    ClxSingletonMEC() {};
    ClxSingletonMEC( const  ClxSingletonMEC  & lxSington) {};
};

ClxSingletonMEC &  InstanceMEC()
{
     static  ClxSingletonMEC Instance;
     return  Instance;
}

并指出,为了防止这个类的用户写出下面的代码:

ClxSingletonMEC lxMEC  =  InstanceMEC();  //  或者ClxSingletonMEC lxMEC(InstanceMEC());

类ClxSingletonMEC的拷贝构造函数必须是private的。
    而purewinter在评论中说道:“还需要把析构函数设为private,否则用户可以错误的delete掉它。”我本来想回复他说,如果析构函数也为private的,那么在程序退出时候调用类的析构函数时就会出现私有成员函数不能访问的错误。
    不过我在回复之前做了个试验。没想到的是,把类ClxSingletonMEC的析构函数设置为private后,程序能编译通过,并且能正常运行!通过在这个private的析构函数中设置断点我发现,这个private的析构函数确实被正常的调用了。
    上面的结果令我非常吃惊!同时也非常迷惑!为什么一个private的析构函数能被正常的调用呢?!这完全推翻了我以前对C++中访问权限(pbulic,protected,private)的理解。
    如果说对象Instance不是静态的,比如函数InstanceMEC()是这样的:

void  InstanceMEC()
{
    ClxSingletonMEC Instance;

//  下面省略……
}

那么,对象Instance在函数InstanceMEC()作用域结束的时候会被析构。这个时候,系统调用对象Instance的析构函数,因为函数InstanceMEC()是类ClxSingletonMEC的友元函数,所以可以访问类所有的成员函数,因此可以调用私有的析构函数将对象Instance析构。这个非常好理解。
    可是,在Singletion模式的例子代码中,类ClxSingletonMEC的友元函数InstanceMEC()中的对象Instance是一个静态对象。而静态对象(不管是全局的还是局部的)是一经构造,就存放在进程中的一个固定内存中,直到进程结束的时候才会由系统调用对象的析构函数而被析构掉。这也是上面的例子代码能保证Instance在进程中唯一的原因(不管用户调用多少次函数InstanceMEC(),只有第一次调用是真正的构造对象Instance,其他的是直接返回对象Instance,这也是static的特性)。也就是说,对象Instance被不是在函数InstanceMEC()中被析构的。那为什么对象Instance的私有析构函数还能被调用呢?
    经过一段时间的思索和代码测试,我发现了“罪魁祸首”--friend。在C++中,friend是破坏封装性的,友元函数可以不受访问权限的限制而访问类的任何成员。在Singletion模式的例子代码中,这正是利用了友元函数的这个特性来访问类的私有构造函数来创建类在进程中的唯一对象的。而C++的访问权限仅仅在源文件中有效,编译时C++编译器确保访问规则,但编译后的目标文件和库文件里是没有任何访问权限信息的。也就是说,由于对象Instance声明在类ClxSingletonMEC的友元函数InstanceMEC()内,在编译阶段编译器就生成了系统可以访问对象Instance的私有构造函数和私有析构函数的目标文件(至于是什么时候调用则是运行期确定的)。而对象Instance是静态的,会存放在进程中的一个固定内存中,是运行时期来决定的。在进程结束时,系统要清空进程堆空间,在调用对象Instance的析构函数时是不会判断该析构函数是否为私有(文件中根本没有任何访问权限信息),因为在编译时期就已经设定对象Instance的私有析构函数是可以被调用的。
    由此可见,C++中friend对封装性的破坏几乎是毁灭性的。

C++中friend对类封装性的强大破坏性相关推荐

  1. 简易售货机JAVA sql_求一个简易自动售货机的代码(java)要用创建类封装性,输出的时候要有提示语句,代码类似以下图片...

    展开全部 //Example类文件Example.java package cn.zhouhan; import java.util.Scanner; public class Example { s ...

  2. Java基础-学习笔记(六)——类的封装性

    1.类是模板,对象是具体的实例 2.如果成员函数中的局部变量与成员变量名一致,则该方法对这个变量名的访问是局部变量 class lesson1 {int age=9;void talk(){int a ...

  3. Python基础学习——面向对象编程(第一讲:面向对象概述、面向对象三个基本特征(封装性、继承性、多态性)、类和对象(定义类、创建和使用对象、实例变量、类变量、构造方法、实例方法、类方法、静态方法))

    面向对象是Python最重要的特性,在Python中一切数据类型都是面向对象的. 1.面向对象概述 面向对象的编程思想是,按照真实世界客观事物的自然规律进行分析,客观世界中存在什么样的实体,构建软件系 ...

  4. Java学习-类的隐藏机制(封装性)

    Java学习-类的隐藏机制(封装性) 1.封装的含义 2.类的setXXX 和 getXXX 3.this关键字 4.总结 1.封装的含义 封装(encapsulation)是面向对象的三要素之一(其 ...

  5. java子类创建过程_JAVA入门小小白学习中ing(匿名对象、封装性、继承性、子类对象的创建过程、spuer关键字(用法一))...

    小小白慢慢学习中ing 第十二天 努力努力 本日内容(匿名对象.封装性.继承性.子类对象的创建过程.spuer关键字) 1.匿名对象 创建对象的语法:Person p1 = new Person(); ...

  6. 类的封装性和信息隐蔽【C++】

    类的封装性和信息隐蔽[C++] 一.公用接口和私有实现的分离 C++通过类来实现封装性,把数据和与这些数据有关的操作封装在一个类中,或者说,类的作用是把数据和算法封装在用户声明的抽象数据类型中. 在类 ...

  7. 【JavaSE】类与对象--封装性

    文章目录 一.面向对象的三大特性 二.封装性 1.什么是封装性? 2.为什么要有封装性? 3.封装性的作用 4.封装性的实现步骤 5.访问限定修饰符 一.面向对象的三大特性 面向对象的三个基本特征是: ...

  8. python语言学习:python语言学习中的定义类、定义函数、封装api等详细攻略

    python语言学习:python语言学习中的定义类.定义函数.封装api等详细攻略 目录 python语言学习中的定义类 python语言学习中的定义函数 python语言学习中封装api pyth ...

  9. java中如何把时间封装成类,java-如何在不使用任何不推荐使用的类的情况下将日期从一种格式转换为另一种格式的日期对象?...

    java-如何在不使用任何不推荐使用的类的情况下将日期从一种格式转换为另一种格式的日期对象? 我想将date1格式的日期转换为date2格式的日期对象. SimpleDateFormat simple ...

最新文章

  1. mysql windows编译_Windows平台下编译Mysql源码 | 学步园
  2. 程序员,请您不要老是熬夜
  3. App Class Loader
  4. opencv 4快速入门_基于OpenCV的图像融合
  5. Vue 模块化开发(构建项目常用工具)
  6. python战斗2:看到一个页面编码
  7. 五菱汽车:并不知悉导致股价及成交量上升的任何原因
  8. python类中变量作用域_python进阶14变量作用域LEGB
  9. 一步一步写算法(之单向链表)
  10. MD5 + salt 的加密算法
  11. source命令执行SQL脚本文件
  12. 管理新语:说说工作的主动权
  13. 【Latex】模板设置及使用教程
  14. dhcp服务器怎么设置虚拟网段,配置DHCP服务器不同网段分配ip
  15. 使用plotly画地图
  16. numpy的文件存储.npy .npz 文件详解
  17. STM32---PB3和PB4引脚
  18. 在线ajax请求工具,-在线工具-postjson
  19. android 模拟器 haxm,Android模拟器不使用HAXM
  20. 编程Verilog四位全加器

热门文章

  1. 机器人:打开潘多拉魔盒
  2. 第十三章 Delphi开发数据库应用程序概述(二)
  3. 《Linux运维实战:使用Percona XtraBackup物理备份与恢复Mysql数据》
  4. undefined和“undefined”
  5. 计算机辅助测试题,2017计算机辅助设计练习题
  6. 再见了新阳丽舍,再见了新雅阁301
  7. 8086与8255实现数码管动态显示
  8. PTGUI全景合成软件使用教程之垂直/水平校正
  9. 中国第二届CSS开发者大会
  10. Aria2GUI for macOS - 百度网盘高速下载