写这篇文章的动机来源于网友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. ORACLE的DUAL表及DB2的SYSIBM.SYSDUMMY1
  2. Unity3d 协程、调用函数、委托
  3. 【AI白身境】深度学习中的数据可视化​​​​​​​
  4. 禁用cookie后怎么使用session_Session 和 Cookie 的区别?你在项目中哪些地方使用了?...
  5. 【翻译】Scott Mitchell的ASP.NET2.0数据指南中文版索引
  6. 【Liunx】Linux vi/vim 教程
  7. 临牌过期保险能理赔吗?
  8. bootstrapTable 取消 “正在加载中...”
  9. Android——距离传感器(PROXIMITY)的应用
  10. 安卓系统格式化SD卡
  11. 漫画:大鱼吃小鱼,小鱼吃虾米。小鱼为什么不能躲起来?
  12. Android App收不到推送的消息
  13. 电脑怎样设置桌面待办,桌面待办事项软件
  14. 萌萌哒身高差(找规律)
  15. 013-Flowcharting实现动态可感知网络拓扑
  16. A_A02_004 J-LINK驱动安装
  17. bugku-细心(想办法变成admin)
  18. navicat连接linux线上MySQL出现2003错误码
  19. pandas 中对axis=0,axis=1的理解,对应pandas中drop的用法
  20. UML之3——图(简介)

热门文章

  1. jmeter两种设置中文方法
  2. day21-办公自动化:利用Python发邮件
  3. 藉由GZipStream的壓縮,來減少Web Service的傳輸量
  4. SharedPreferencesUtil工具类
  5. 【建议收藏】2023年最新最全PMP 报考条件和流程在这里!
  6. python就业前景不好_Python就业前景好吗?女生适合吗?
  7. 一加3 android 8.0,OnePlus 3公测版固件完整rom包Android 8.0第15版
  8. 股票下单软件接口的设计原则是什么?
  9. 弹性布局之em的用法!
  10. java 音频倍速播放_Android MediaPlayer 音频倍速播放,调整播放速度