C++句柄解析
C++句柄类解析
引题:在C++中,对于运行时类型识别问题。在程序中使用引用或者指针在运行时动态识别对象类型。然而使用指针或者引用却增加了用户负担(在继承体系中,没有明确的基类到派生类的转换,必须用户显示转换并将结果对象加入容器中。但是这样的做法结果却是派生对象部分成员是未初始化的)。
对于这一问题,可以将对象指针 保存在容器中来解决。但此时,用户必须明确容器中指针和 对象的同步性(不能只有指针而对象不存在或者收指针不存在,对象存在)。
更好的解决方案就是句柄类了:
C++ 中一个通用的技术是定义包装(cover)类或句柄类。句柄类存储和管 理基类指针。指针所指对象的类型可以变化,它既可以指向基类类型对象又可以 指向派生类型对象。用户通过句柄类访问继承层次的操作。因为句柄类使用指针 执行操作,虚成员的行为将在运行时根据句柄实际绑定的对象的类型而变化。因 此,句柄的用户可以获得动态行为但无须操心指针的管理。
包装了继承层次的句柄有两个重要的设计考虑因素:
- 对任何保存指针的类一样,必须确定对复制控制做些什 么。包装了继承层次的句柄通常表现得像一个智能指针 或者像一个值。
- 句柄类决定句柄接口屏蔽还是不屏蔽继承层次,如果不屏蔽继承层次,用 户必须了解和使用基本层次中的对象。
①指针型句柄:
句柄包装指针,用户可以将该句柄类当作指针使用,却不用去管理指针指向的对象。(句柄类更像是一个中介控制者)
定义方案:
1. 使用类包装指针,包装计数器(每个对象都有各自的这两个成员)
2.使用类包装指针,包装计数器指针(资源和计数器共享)
句柄类除了定义构造,拷贝构造,赋值,还需要定义引用,解引用(使之看起来更像是指针)
对于构造函数:
1个默认构造函数初始化成员为0;
1个构造函数声明指定对象类型的句柄。
那么问题来了,如果用户并不知晓用 继承体系中具体哪个层次对象进行初始化,如何做呢。
解决这个问题的通用方法是定义虚操作进行复制,我们称将 该操作命名为 clone。(克隆):
对于继承层次中的每个类,增加一个虚克隆函数eg:
class Item_base
{
public:
virtual Item_base* clone() const
{
return new Item_base(*this);
}
};
有了克隆函数那么 句柄类的定义如下:
Sales_item::Sales_item(const Item_base &item):
p(item.clone()), use(new std::size_t())
{ }
对于继承层次中 如果需要逻辑比较函数,一个好的做法是 定义内部比较,比较内部核心成员。
inline bool
compare(const Sales_item &lhs, const Sales_item &rhs)
{
return lhs->book() < rhs->book();
}
使用带关联容器的比较器
要有效地工作,关联容器需要对每个操作使用同一比较函数。然而,期望用 户每次记住比较函数是不合理的,尤其是,没有办法检查每个调用使用同一比较 函数。因此,容器记住比较函数是有意义的。通过将比较器存储在容器对象中, 可以保证比较元素的每个操作将一致地进行。
这种做法,实质上就是使用函数指针,函数回调实现真正的比较。
// type of the comparison function used to order the multiset
typedef bool (*Comp)(const Sales_item&, const Sales_item&);
关联容器的每个构造函数使我们能够提供比较函数的名 字。可以这样定义使用 compare 函数的空 multiset:
std::multiset<Sales_item, Comp> items(compare);
multiset 是STL中的联合容器。。在头文件<set>中,具体用法请参看《STL源码剖析》
参考(C++primer)
C++句柄解析的更多相关文章
- (转)WINDOWS内核对象
WINDOWS内核对象 原文地址:http://blog.csdn.net/misterliwei/article/details/976988 支持原创 一.前言 Windows中有很多像进程对象 ...
- 在C++中使用C#编写的类2
在那篇<在C#中使用C++编写的类>中我介绍了如何在C#中使用C++编写的类.可是由于C#在用户界面设计.数据库存储和XML文件读取等方面的优势,有时候也会出现要在C++中使用C#编写的类 ...
- JDK8中JVM对类的初始化探讨
在<深入理解Java虚拟机>(第二版,周志明著)中,作者介绍了JVM必须初始化类(或接口)的五种情况,但是是针对JDK7而言的. 那么,在JDK8中,这几种情况有没有变化呢?(我猜测应该会 ...
- JDK 8 - JVM 对类的初始化探讨
在<深入理解 Java 虚拟机>(第二版,周志明著)中,作者介绍了 JVM 必须初始化类(或接口)的五种情况,但是是针对 JDK 7 而言的. 那么,在 JDK 8 中,这几种情况有没有变 ...
- C#与西门子PLC通讯
1.0 通讯组件概述 通讯组件用于PC与可编程控制器(PLC).智能仪表等进行数据通讯,适用于基于PC高级语言的工业自动化控制系统.组件采用动态链接库文件(*.DLL)的形式,在PC系统的项目工程里 ...
- JVM解毒——类加载子系统
带着问题,尤其是面试问题的学习才是最高效的.加油,奥利给! 点赞+收藏 就学会系列,文章收录在 GitHub JavaEgg ,N线互联网开发必备技能兵器谱 直击面试 看你简历写得熟悉JVM,那你说说 ...
- JVM详解之:类的加载链接和初始化
目录 简介 加载 运行时常量池 类加载器 链接 验证 准备 解析 初始化 总结 简介 有了java class文件之后,为了让class文件转换成为JVM可以真正运行的结构,需要经历加载,链接和初始化 ...
- React-Native知识点相关
React-Native相关 一,为什么要使用React-native? Hybrird的首屏时间太慢,白屏太久,影响用户体验: 原生native开发成本较高: 这里补充一点Webview的性能优化: ...
- JVM之类加载器子系统
类加载器子系统 作用 负责从文件系统或网络系统中加载class文件,class文件在开头有特殊的标记(魔术开头CA FE BA BE) ClassLoader只负责加载class文件,至于能否运行,由 ...
随机推荐
- PrimeNG之DataTable
--数据表显示在表格格式数据. Basic Import import {DataTableModule,SharedModule} from 'primeng/primeng'; source &l ...
- 基于Enterprise Architect完成数据库建模
基于Enterprise Architect完成数据库建模 “工欲善其事必先利其器”,Enterprise Architect是一款非常便利的设计工具,目前我也是刚刚使用没多久,进行过系统设计.UML ...
- MongoDB 目录
MongoDB 介绍 centos7.6 安装与配置 MongoDB yum方式 MongoDB 数据库操作 MongoDB 用户管理 MongoDB 新建数据库和集合 查询集合 MongoDB 增删 ...
- django 1.11 目录
django 信号 django form
- python类型错误:'NoneType' object is not subscriptable
TypeError: 'NoneType' object is not subscriptable --> 原因:变量使用了系统内置的关键字list 解决:重新定义下这个变量
- pandas的Panel类型dtype
panel = pd.Panel(dataframe_dict) 把一个多列类型不相同(里面有int,float)的dataframe字典直接赋值给Panel,从Panel中解析出来的datafram ...
- Jenkins Pipeline脚本
node { echo 'Hello World' } node 在Jenkins环境中分配一个执行器和工作空间. echo 在控制台输出中写入简单的字符串 try { timeout(time: 1 ...
- python-17
# 列表生成式 a = [x*2 for x in range(10)] # 这两个变量必须一致 print(a) #列表 元组的高级赋值办法 b,c = [",6] # python的垃圾 ...
- sublime开启vim模式
sublime自带vim模式Vintage,只是默认是ignore状态,因此如果按Esc键没有进入vim模式,只需要按ctrl+shift+P进入命令模式,键入Enable package,输入Vim ...
- Numpy 数据类型和基本操作
Numpy 数据类型 bool 用一位存储的布尔类型(值为TRUE或FALSE) inti 由所在平台决定其精度的整数(一般为int32或int64) int8 整数,范围为128至127 int1 ...