一、重新编译问题
我们先来看一个在实际中可能遇到的问题:
比如现在建立好了一个dll导出了cmyclass类,客户也能正常使用这个dll,假设cmyclass对象的大小为30字节。如果我们需要修改dll中的cmyclass类,让它有相同的函数和成员变量,但是给增加了一个私有的成员变量int类型,现在cmyclass对象的大小就是34字节了。当直接把这个新的dll给客户使用替换掉原来30字节大小的dll,客户应用程序期望的是30字节大小的对象,而现在却变成了一个34字节大小的对象,糟糕,客户程序出错了。
类似的问题,如果不是导出cmyclass类,而在导出的函数中使用了cmyclass,改变对象的大小仍然会有问题的。这个时候修改这个问题的唯一办法就是替换客户程序中的cmyclass的头文件,全部重新编译整个应用程序,让客户程序使用大小为34字节的对象。
这就是一个严重的问题,有的时候如果没有客户程序的源代码,那么我们就不能使用这个新的dll了。
二、解决方法
为了能避免重新编译客户程序,这里介绍两个方法:(1)使用接口类。(2)使用创建和销毁类的静态函数。
1、使用接口类
接口类的也就是创建第二个类,它作为要导出类的接口,所以在导出类改变时,也不需要重新编译客户程序,因为接口类没有发生变化。
假设导出的cmyclass类有两个函数functiona functionb。现在创建一个接口类cmyinterface,下面就是在dll中的cmyinterface类的头文件的代码:
# include "myclass.h"
class _declspec(dllexport) cmyinterface
{
cmyclass *pmyclass;
cmyinterface();
~cmyinterface();
public:
int functiona(int);
int functionb(int);
};
而在客户程序中的头文件稍不同,不需要include语句,因为客户程序没有它的拷贝。相反,使用一个cmyclass的向前声明,即使没有头文件也能编译:
class _declspec(dllexport) cmyinterface
{
class cmyclass;//向前声明
cmyclass *pmyclass;
cmyinterface();
~cmyinterface();
public:
int functiona(int);
int functionb(int);
};
在dll中的cmyinterface的实现如下:
cmyinterface::cmyinterface()
{
pmyclass = new cmyclass();
}
cmyinterface::~cmyinterface()
{
delete pmyclass;
}
int cmyinterface::functiona()
{
return pmyclass->functiona();
}
int cmyinterface::functionb()
{
return pmyclass->functionb();
}
.....
对导出类cmyclass的每个成员函数,cmyinterface类都提供自己的对应的函数。客户程序与cmyclass没有联系,这样任意改cmyclass也不会有问题,因为cmyinterface类的大小没有发生变化。即使为了能访问cmyclass中的新增变量而给cmyinterface类加了函数也不会有问题的。
但是这种方法也存在明显的问题,对导出类的每个函数和成员变量都要对应实现,有的时候这个接口类会很庞大。同时增加了客户程序调用所需要的时间。增加了程序的开销。
2、使用静态函数
还可以使用静态函数来创建和销毁类对象。创建一个导出类的时候,增加两个静态的公有函数createme()/destroyme(),头文件如下:
class _declspec(dllexport) cmyclass
{
cmyclass();
~cmyclass();
public:
static cmyclass *createme();
static void destroyme(cmyclass *ptr);
};
实现函数就是:
cmyclass * cmyclass::cmyclass()
{
return new cmyclass;
}
void cmyclass::destroyme(cmyclass *ptr)
{
delete ptr;
}
然后象其他类一样导出cmyclass类,这个时候在客户程序中使用这个类的方法稍有不同了。如若想创建一个cmyclass对象,就应该是:
cmyclass x;
cmyclass *ptr = cmyclass::createme();
在使用完后删除:
cmyclass::destroyme(ptr);
文章整理:站长天空 网址:http://www.z6688.com/
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!




