《COM本质论》COM是一个更好的C++心得分享
昨天看了《COM本质论》的第一章”COM是一个更好的C++”,认为非常有必要做一些笔记,于是整理成这篇文章。我相信你值得拥有。
这篇文章主要讲的内容是:一个实现了高速查找功能的类FastString,在一个小小的需求之后,慢慢的演变成一个COM组件的过程。
类FastString实现了一个高速查找字符串的功能。快到时间复杂度是O(1),我们先无论作者是怎么实现的,预计是通过空间换时间。
因为这个类查找字符串非常快,于是作者就把这个类当做一个产品,以源代码的方式卖给须要的厂商。厂商用后感觉非常好。但有的厂商想要获得字符串长度的功能,他们认为strlen(str)速度太慢,毕竟这个函数获取字符串的长度是线性的,时间复杂度是O(N),于是作者决定改动他的FastString。其内心一直在告诉自己:我的FastString必须是Fast。
我们先来看看作者FastString的样子:
class FastString
{
public:
FastString(const char* str);
FastString(void );
int Find (const char* str );
private:
char* m_str ;
};
可别小看这个类,它查找字符串可快了(我也不知道为什么它就他妈的这么快)。聪明的作者听了厂商的需求之后,非常快的就想到了非常好的解决方式,通过一个变量len来存字符串的长度,通过一个函数Length返回变量len,时间复杂度但是O(0)哦,于是作者非常快的实现了厂商的需求。大概例如以下:
class FastString
{
public:
FastString(const char* str);
FastString(void );
int Length ();//新增的
int Find (const char* str );
private:
char* m_str ;
int len ;//新增的
};
在经过天衣无缝的測试之后。作者骄傲的将他的作品分发给了愿意再次掏钱的厂商。厂商用了非常是火大,出现了各种莫名其妙的问题,在被各个厂商咆哮之后,作者发现了他的作品的缺陷,于是决定走上COM之路。
我们先来看看厂商用了作者的FastString之后为什么就挂了呢?
厂商们拿了作者的源代码之后。就以源代码的方式和自己的其它代码一起编译成一个DLL文件,然后让自己的产品升级。升级就是简单的覆盖这个DLL文件,于是厂商的产品升级之后就挂了。
由于FastString可能在多个DLL中多个文件都实例化了,在这些DLL中FastString占用4个字节的内存,而新版本号的FastString占用的是8个字节的内存,厂商仅仅覆盖了FastString所在的DLL,而没有覆盖全部使用了FastString的DLL。由于FastString所在的DLL创建FastString是8个字节,而其它DLL中是4个字节。假设跨库传递FastString,将一个4字节的对象当做一个8字节的对象来用,这还不挂。
聪明的作者非常快就实现了他的COM组件,源代码大概是以下这个样子,不要奇怪为什么作者的COM之路这么顺风顺水。这么快就出了作品。
#pragma once
class IExtensibleObject
{
public:
virtual void* Dynamic_Cast(const char* str)=0;
virtual void AddRef()=0;
virtual void Release()=0;
}; class IFastString:public IExtensibleObject
{
public:
virtual int Length(void)=0;
virtual int Find(const char* str)=0;
}; class FastString:public IFastString
{
public:
FastString(const char* str=NULL);
virtual void* Dynamic_Cast(const char* str);
virtual void AddRef() ;
virtual void Release();
virtual int Length();
virtual int Find(const char* str);
~FastString();
private:
char* m_str;
int len;
int m_cPtrs;//引用计数
}; //导出函数
extern "C" __declspec(dllimport) IFastString* CreateFastString(const char* psz);
作者的COM组件做到了一下几点,最终实现了增量更新。文章參考游戏编程网www.cgzhw.com资料。特此注明。
1:作者不在以源代码的方式卖给厂商。而是以头文件和库的方式卖个厂商。厂商能够通过静态/动态的方式链接作者的库。
2:作者不在让厂商到处实例化他的FastString。我可爱的FastString。
而是通过一个导出函数实例化FastString,并返回IFastString。这样就不会出现不同DLL中FastString实例大小不一样的问题。如今全部的实例都在作者的DLL中创建了。
3:关于回收FastString的问题?作者刚開始是想直接delete掉CreateFastString返回的指针,但为了实现COM组件,此时的FastString已经不是彼时的自己了,他继承并实现了多个接口,因为接口之间转换来转换去,都不知道删除哪个指针了。于是作者决定通过使用引用计数的方式销毁FastString。
4:为什么要自己实现Dynamic_Cast?
RTTI是一个与编译器极为相关的特征,每一个编译器厂商对RTTI的实现是独有的,这大大破坏了“以抽象基类作为接口而获得的编译器独立性”,既然每一个编译器可能有不同的实现,即析构函数不能定义成虚函数,由于不同的编译器。虚函数在虚方法表中的位置是不一样的,有的编译器放在最前面有的放在最后面,这会导致不同的编译器编译后虚方法在虚方法表中的位置是不一样的。
所以析构函数不能定义成virtual,其它public接口都必须定义成virtual。其它虚方法在虚方法表中的位置和虚方法的声明保持一致,即依照声明的顺序存放在虚方法中。
因为类型转换和引用计数是每一个接口都须要的,于是把他们提出来放到最顶层。让全部的接口继承它。
5:新增的接口仅仅能加在最后面,废弃的接口不能删除。
假设新增的接口插在中间。那么部分接口在虚方法表中的地址就会发生变化。新版本号的DLL就不能与已经公布的程序兼容,就不能实现增量升级,即仅仅用覆盖某个DLL,而不须要所有都要更新,废弃的接口删除会导致相同的问题。
《COM本质论》COM是一个更好的C++心得分享的更多相关文章
- COM是一个更好的C++
昨天看了<COM本质论>的第一章”COM是一个更好的C++”,觉得很有必要做一些笔记,于是整理成这篇文章,我相信你值得拥有. 这篇文章主要讲的内容是:一个实现了快速查找功能的类FastSt ...
- [Swift]LeetCode496. 下一个更大元素 I | Next Greater Element I
You are given two arrays (without duplicates) nums1 and nums2 where nums1’s elements are subset of n ...
- [Swift]LeetCode503. 下一个更大元素 II | Next Greater Element II
Given a circular array (the next element of the last element is the first element of the array), pri ...
- [Swift]LeetCode1019. 链表中的下一个更大节点 | Next Greater Node In Linked List
We are given a linked list with head as the first node. Let's number the nodes in the list: node_1, ...
- Leetcode 496. 下一个更大元素 I
1.题目描述 给定两个没有重复元素的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集.找到 nums1 中每个元素在 nums2 中的下一个比其大的值. nums1 中数字 ...
- 下一个更大的数 Next Greater Element
2018-09-24 21:52:38 一.Next Greater Element I 问题描述: 问题求解: 本题只需要将nums2中元素的下一个更大的数通过map保存下来,然后再遍历一遍nums ...
- LeetCode--496--下一个更大元素I(java)
给定两个没有重复元素的数组 nums1和 nums2 ,其中nums1 是 nums2 的子集.找到 nums1 中每个元素在 nums2 中的下一个比其大的值. nums1 中数字 x 的下一个更大 ...
- [Leetcode]下一个更大元素II
题目 给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素.数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地 ...
- Leetcode 503. 下一个更大元素 II
1.题目描述 给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素.数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应 ...
随机推荐
- C/C++开发平时用的自定义debug函数
一.无颜色版 一.自定义printf #include <stdio.h> #ifdef MYDEBUG #define DEBUG(arg...) {\ printf("[de ...
- 小案例:struts1.3利用nested标签使用POJO
其中的关键就是这个POJO是你自己去new一个,struts是不会帮你创建的!参考http://luohua.iteye.com/blog/39976 表单页 <%@ page language ...
- js 阻止事件冒泡 支持所有主流浏览器
function getEvent(){ if(window.event) {return window.event;} func=getEvent.caller; while(func!=null) ...
- spring mvc中拦截器配置mvc:interceptors
其实在mvc:interceptors标签中,有两种类型的配置,一种直接配置一个bean(bean和ref归为一类),另一种还要配置上拦截的路径和排除的路径.直接配置的bean那就代表对所有的请求进行 ...
- 解决windows server 2008 r2 右键没有个性化
装完系统发现桌面上只有一个回收站我的电脑 网络邻居 控制板面都没有好像win7家庭版也没有右键–个性化设置上google百度了下 也还漫简单的点左下角的开始-运行:"C:\Windows\s ...
- hdu6035 Colorful Tree 树形dp 给定一棵树,每个节点有一个颜色值。定义每条路径的值为经过的节点的不同颜色数。求所有路径的值和。
/** 题目:hdu6035 Colorful Tree 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6035 题意:给定一棵树,每个节点有一个颜色值.定 ...
- Jmeter负载测试例子
通过浏览器操作网站在jmeter录屏控制器显示录屏例子,并且通过这例子模拟多用户(线程)来负载测试. 工具/原料 Jmeter 浏览器 1.先在测试计划创建线程组和录制Case 1 1.1 选 ...
- 判断下列语句是否正确,如果有错误,请指出错误所在?interface A{
判断下列语句是否正确,如果有错误,请指出错误所在? interface A{ int add(final A a); } class B implements A{ long add(final A ...
- (转)git使用教程
git基础使用:http://geek.csdn.net/news/detail/77455 github介绍:http://stormzhang.com/github/2016/05/25/lear ...
- 一起talk C栗子吧(第一百二十七回:C语言实例--查看main函数的參数)
各位看官们,大家好,上一回中咱们说的是static关键字的样例,这一回咱们说的样例是:查看main函数的參数.闲话休提,言归正转.让我们一起talk C栗子吧! 看官们.我们在第五十七回中介绍过mai ...