由于不同的编译器对函数的命名方法不同,使跨编译器进行动态库调用变得困难。对于调用g++的一般函数,在dev编写库文件时,在头文件中函数前声明extern "C",然后可以直接在vc中调用,但这种方法对于类是不行的。
下面介绍两种调用导出类的方法。
1.我们利用vc可以调用普通函数库的能力,将类成员函数全部转化为普通函数进行调用,这种方法的缺点是调用麻烦,封装性不好。
2.类似COM原理,我们用dev建立一个中间dll库,然后让vc调用这个中间库。在该库中,在头文件中建立一个抽象类,抽象类中的成员函数为要调用的链接库中的类的成员函数,并声明为虚函数,另外添加两个普通函数,作为与外界的接口,得到一个对象的指针和释放该指针,然后在源文件中建立它的派生类,添加一个成员变量为要导入类的对象,重写基类的成员函数,实现时利用成员变量调用导入类的函数。
例如,我们有一个只有声明的类,和其实现的dll和动态导入库.a文件。
class DLLIMPORT Column
{
public:
Column(double r,double h);
virtual ~Column(void);
double GetArea();
double GetVolume();
void SetRadical(double r);
void SetHeight(double h);
private:
double radical;
double height;
};
然后建立一个中间库,调用原始库,头文件声明为
class baseColumn
{
public:
virtual double _stdcall GetArea()=0;
virtual double _stdcall GetVolume()=0;
virtual void _stdcall SetRadical(double r)=0;
virtual void _stdcall SetHeight(double h)=0;
private:
};
extern "C"{
DLLIMPORT baseColumn* _stdcall new_Column(double r,double h);
DLLIMPORT void _stdcall delete_Column(baseColumn* bc);
}
实现中,定义一个派生类
class ColumnImp1:public baseColumn
{
private:
Column m_Column;
public:
_stdcall ColumnImp1(double r,double h);
virtual double _stdcall GetArea();
virtual double _stdcall GetVolume();
virtual void _stdcall SetRadical(double r);
virtual void _stdcall SetHeight(double h);
};
每个实现调用Column类的成员函数,
_stdcall ColumnImp1::ColumnImp1(double r,double h):m_Column(r,h){}
double _stdcall ColumnImp1::GetArea()
{
return m_Column.GetArea();
}
double _stdcall ColumnImp1::GetVolume()
{
return m_Column.GetVolume();
}
void _stdcall ColumnImp1::SetRadical(double r)
{
m_Column.SetRadical(r);
}
void _stdcall ColumnImp1::SetHeight(double h)
{
m_Column.SetHeight(h);
}
实现普通接口函数,
baseColumn* _stdcall new_Column(double r,double h)
{
return new ColumnImp1(r,h);
}
void _stdcall delete_Column(baseColumn* bc)
{
delete bc;
}
在vc源程序中调用中间库,采用显式链接如下,
typedef baseColumn* (*pc1)(double,double);
typedef void (*pc2)(baseColumn*);
HINSTANCE Hind=LoadLibrary("libvirclass.dll");
pc1 f1=(pc1)GetProcAddress(Hind,"new_Column");
pc2 f2=(pc2)GetProcAddress(Hind,"delete_Column");
baseColumn* bc=f1(1,1);
cout<<bc->GetVolume()<<endl;
cout<<bc->GetArea()<<endl;
bc->SetRadical(2);
bc->SetHeight(2);
cout<<bc->GetVolume()<<endl;
cout<<bc->GetArea()<<endl;
f2(bc);
需要注意的地方是在声明普通函数时前面添加 extern "C",指定采用c编译方式,在中间库中类的所有函数都指定为_stdcall函数调用约定,同样vc中默认调用约定为_cdecl,更改为_stdcall,使保持一致。