正在阅读:经典编程:DLL地狱及其解决方案经典编程:DLL地狱及其解决方案

2004-05-17 10:05 出处:CSDN 作者:happydeer(翻译) 责任编辑:linjixiong
(5)发布两个版本的DLL和LIB文件(Debug版本和Release版本)。因为如果只发布Release版本,开发者将无法调试他们的程序,因为Release版与Debug版使用了不同的堆(Heap)管理器,因而当Debug版本的客户程序释放Release版本DLL申请的内存时,会导致运行时错误(Runtime failure)。有一种办法可以解决这个问题,就是DLL同时提供申请和释放内存的函数供客户程序调用;DLL中也保证不释放客户程序申请的内容。通常遵守这个约定不是那么简单!    (6)在编译的时候,不要改变DLL导出类函数的默认参数,如果这些参数将被传递到客户程序的话。    (7)注意内联(inline)函数的更改。    (8)检查所有的枚举没有默认的元素值。因为当增加/删除一个新的枚举成员,你可能移动旧枚举成员的值。这就是为什么每一个成员应该拥有一个唯一标识值。如果枚举可以被扩展,也应该对其进行文档说明。这样,客户程序开发者就会引起注意。    (9)不要改变DLL提供的头文件中定义的宏。      2. 对DLL进行版本控制:如果主要的DLL发生了改变,最好同时将DLL文件的名字也改掉,就象微软的MFC DLL一样。例如,DLL文件可以按照如下格式命名:Dll_name_xx.dll,其中xx就是DLL的版本号。有时候DLL中做了很大的改动,使得向后兼容性问题无法解决。此时应该生成一个全新的DLL。将这个新DLL安装到系统时,旧的DLL仍然保留。于是,旧的客户程序仍然能够使用旧的DLL,而新的客户程序(使用新DLL编译、连接)可以使用新的DLL,两者互不干涉。      3. DLL的向后兼容性测试:还有很多很多中可能会破坏DLL的向后兼容性,因此实施DLL的向后兼容性测试是非常必要的!      接下去,我将来讨论一个虚函数的问题,以及对应的一个解决方案。      虚函数与继承      首先来看一下如下的虚函数和继承结构:      /**********DLL导出的类 **********/   class EXPORT_DLL_PREFIX VirtFunctClass{   public:    VirtFunctClass(){}    ~VirtFunctClass(){}    virtual void DoSmth(){    //this->DoAnything();    // Uncomment of this line after the corresponding method    //will be added to the class declaration    }    //virtual void DoAnything(){}    // Adding of this virtual method will make shift in    // table of virtual methods   };      /**********客户程序,从DLL导出类派生一个新的子类**********/   class VirtFunctClassChild : public VirtFunctClass {   public:    VirtFunctClassChild() : VirtFunctClass (){}    ~VirtFunctClassChild(){};    virtual void DoSomething(){}   };      假设上面的两个类,VirtFunctClass在my.dll中实现,而VirtFunctClassChild在客户程序中实现。接下去,我们做一些改变,将如下两个注释行放开:   //virtual void DoAnything(){}   和   //this->DoAnything();      也就是说,DLL导出的类作了改动!现在如果客户程序没有重新编译,那么客户程序中的VirtFunctClassChild将不知道DLL中VirtFunctClass类已经改变了:增加了一个虚函数void DoAnything()。因此,VirtFunctClassChild类的虚函数表仍然包含两个函数的映射:   1. void DoSmth()   2. void DoSomething()      而事实上这已经不对了,正确的虚函数表应该是:   1. void DoSmth()   2. void DoAnything()   3. void DoSomething()      问题就在于,当实例化VirtFunctClassChild之后,如果调用它的void DoSmth()函数,DoSmth()函数转而要调用void DoAnything()函数,但此时基类VirtFunctClass只知道要调用虚函数表中的第二个函数,而VirtFunctClassChild类的虚函数表中的第二个函数仍然是void DoSomething(),于是问题就出来了!      另外,禁止在DLL的导出类的派生类(上例中的VirtFunctClassChild)中增加虚函数也是于事无补的。因为,如果VirtFunctClassChild类中没有virtual void DoSomething()函数,基类中的void DoAnything()函数(虚函数表中的第二个函数)调用将会指向一个空的内存地址(因为VirtFunctClassChild类维持的虚函数表仅仅维持有一个函数地址)。
察看评论详细内容 我要发表评论
作者笔名 简短内容 发表时间
:
键盘也能翻页,试试“← →”键

关注我们

最新资讯离线随时看 聊天吐槽赢奖品