由于不同的編譯器對函數的命名方法不同,使跨編譯器進行動态庫調用變得困難。對于調用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,使保持一緻。