注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

写着玩

Bob

 
 
 

日志

 
 
 
 

COM 本质论 读书笔记 1  

2008-12-18 17:01:38|  分类: COM |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

 

这是COM领域最负盛名的一本书,但是它不是供新手学习的书,也不是教你如何开发COM的书。如果对COM缺乏基本的了解,建议先学习《COM原理与应用》。

         大多数经典的面向对象的课本都认为,只要一个系统或一种语言支持封装、继承、多态,那么他就是面向对象的。继承性通常被强调为实现重用性的主要工具。但是COM设计者不同意这种观点,他们认为这是一种过于简单的看法,实际上存在两种继承:实现继承(行为的继承)和接口继承(行为规范的继承)。实现继承导致基类和派生类的过分耦合。泄漏基类的细节,破坏了封装性。COM用于构建重用性的基础概念是封装而不是继承。

 面向对象程序设计和面向组件程序设计的区别:

面向对象= 多态+某些迟绑定+某些封装性+继承

面向组件= 多态+完全迟绑定+完全封装性+接口继承+二进制重用

 

第一章   COM是一个更好的C++

         C++的一个主要目的是允许程序员建立用户自定义类型(UDT),而且这些类型可以在原始实现环境之外被重用。这条原则巩固了我们今天所熟知的类库或者框架的基础。重用性一直是面向对象的主要动机之一。这一章主要介绍了要把C++类做成可重用的组件所面临的挑战。展示了一个可重用得组件结构,这个结构允许多个独立开发的二进制组件嫩购动态、有效的组成一个复合系统。

         从传统意义上讲,C++类库一直以原代码的形式分发。用户可以把实现代码加入他们的系统工程中,如何用它们的编译器重新编译库代码。代码重用带来的问题:

1.  每个应用的可执行文件包含了一份类库的代码,都将占用一份磁盘空间以及一份虚拟内存

2.  一旦发现缺陷,没有任何办法替换部分实现代码

3.  为了重用必须理解其他开发人员的设计和变成风格,不仅要理解封装在库内部的底层技术还需要理解库本省强加的抽象概念。

4.  缺少文档,通常都假定库的用户把哭得源代码当作最根本的参考材料。导致客户应用和类库之间过分耦合,也使得整个代码随着时间的推移变得脆弱。

5.  常常会产生更加适合程序员应用的私有build版本,而不是真正的原始版本。

         为了解决上面的问题的一种技术是把代码一动态链接库的形式包装起来。一旦确定了要以DLL的形式发布一个C++类,将面临C++的基本弱点:C++缺少二进制一级的标准。面临的问题:

1.  需要处理连接问题:为了允许操作符重载和函数重载,采用了名字改编技术。可以采用DEF文件解决

2.  需要处理最终产生代码相关的问题:比如异常

3.  需要解决封装性的问题:C++编译模型要求客户的编译气必须能够访问与对象的内存布局有关的信息,这样才能构造出类的实例,或者调用类的非虚拟成员函数。这些信息包括对象的私有成员和公共成员的大小和顺序。库更新版本后,如果类的成员顺序或大小改变了,那么将导致原有客户程序无法成功调用。通用解决办法是每次新版本问世后就把DLL改称其他名字,比如MFC。

试验:

DLL代码

 

class __declspec(dllexport) CClass1

{

private:

     void PFun1(){}

public:

     CClass1(void);

     virtual~CClass1(void);

     void Fun2();

     void Fun1();

private:

     int m_nData5;

     int m_nData6;

};

编译导入客户程序,

{

。。。

     CClass1* pcl=new CClass1;

     pcl->Fun1();

     delete pcl;

。。。

}

之后将DLL的类改为:

 

class __declspec(dllexport) CClass1

{

private:

     void PFun1(){}

public:

     CClass1(void);

     virtual~CClass1(void);

     void Fun2();

     void Fun1();

private:

     int m_nData51;

     int m_nData1;

     int m_nData23;

     int m_nData54;

     int m_nData0;

     int m_nData5;

     int m_nData6;

};

重新编译生成DLL,覆盖原有版本,客户程序crash。

试验得知:

1.  如果将新增加的私有变量增加到原私有变量之后运行正常,说明VC编译器对私有变量的排序和书写顺序有关。

2.  与新增变量个数有关,少了可能正常,同时与变量是否初始化以及初始化顺序似乎也有关系(未完全验证)  

要解决DLL所带来的问题,需要构造一个模型,把两个抽象的概念(接口和实现)做成两个分离的实体,即C++类。定义一个C++类使他代表指向一定的数据类型的接口,定义另一个作为数据类型的实际实现。我们需要一种方法,它能够把接口和实现联系起来,但是又不会向客户暴露任何实现细节。一个简单的办法就是用一个句柄类作为接口。句柄类只包含一个实体指针,在客户范围内他的类型永远不需要被完全定义出来。使用这项技术接口方法的机器码变成了对象DLL的唯一入口点,他们的二进制结构形式永远也不会再改变。接口类方法的实现只是把方法调用传递给实际的实现类。带来的问题是接口类必须把每个方法调用显式的传递给实现类,对于大的类库,负担很大。同时句柄类并没有完全解决编译器/连接器兼容性的问题,而这正是我们实现可重用组件所必须要解决的问题。

  评论这张
 
阅读(128)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017