写在前面
从DLl中导出类,这里分成两种情况:
① 导出类中所有成员
② 只导出指定成员
导出类中所有成员
在声明类时指定 __declspec(dllexport) 导出声明,即可默认导出类的所有成员函数.
为方便观察先屏蔽先前Dll1项目的全局导出函数代码.
修改Dll1.h头文件如下:
//Dll1.h
#ifdef DLL1_API
#else
#define DLL1_API __declspec(dllimport)
#endif
//int __declspec(dllimport) add(int a, int b);
//extern int DLL1_API add(int a, int b);
//int __declspec(dllimport) subtract(int a, int b);
//extern int DLL1_API subtract(int a, int b);
class DLL1_API Dll1
{
public:
Dll1();
virtual ~Dll1();
void publicFun();
public:
int m_nVal;
private:
void privateFun();
int m_nVal2;
};
修改Dll1.cpp源文件如下:
//Dll.cpp
#define DLL1_API __declspec(dllexport)
#include "Dll1.h"
//int add(int a, int b)
//{
// return a + b;
//}
//
//int subtract(int a, int b)
//{
// return a - b;
//
#include <windows.h>
#include <tchar.h>
Dll1::Dll1() : m_nVal(0), m_nVal2(0)
{
TCHAR buf[100] = { 0 };
_stprintf_s(buf, _T("\nDll1默认构造--m_nVal = %d\n"), m_nVal);
OutputDebugString(buf);
}
Dll1::~Dll1()
{
OutputDebugString(_T("\nDll1析构\n"));
}
void Dll1::publicFun()
{
OutputDebugString(_T("\nDll1--publicFun\n"));
}
void Dll1::privateFun()
{
OutputDebugString(_T("\nDll1--privateFun\n"));
}
重新生成后使用dumpbin命令查看:
发现并没有两个int型成员变量的相关信息,即这种方式不能导出类的成员变量吗? 后面指定导出时确定是不能导出的.
只导出指定成员
在需要指定导出的函数声明中加 __declspec(dllexport) 即可.
修改Dll1.h头文件如下:
//Dll1.h
#ifdef DLL1_API
#else
#define DLL1_API __declspec(dllimport)
#endif
//int __declspec(dllimport) add(int a, int b);
//extern int DLL1_API add(int a, int b);
//int __declspec(dllimport) subtract(int a, int b);
//extern int DLL1_API subtract(int a, int b);
class /*DLL1_API*/ Dll1
{
public:
Dll1();
virtual ~Dll1();
void DLL1_API publicFun();
public:
int /*DLL1_API*/ m_nVal;
private:
void DLL1_API privateFun();
int /*DLL1_API*/ m_nVal2;
};
修改Dll1.cpp源文件如下, 和上面相比无变化
//Dll.cpp
#define DLL1_API __declspec(dllexport)
#include "Dll1.h"
//int add(int a, int b)
//{
// return a + b;
//}
//
//int subtract(int a, int b)
//{
// return a - b;
//
#include <windows.h>
#include <tchar.h>
Dll1::Dll1() : m_nVal(0), m_nVal2(0)
{
TCHAR buf[100] = { 0 };
_stprintf_s(buf, _T("\nDll1默认构造--m_nVal = %d\n"), m_nVal);
OutputDebugString(buf);
}
Dll1::~Dll1()
{
OutputDebugString(_T("\nDll1析构\n"));
}
void Dll1::publicFun()
{
OutputDebugString(_T("\nDll1--publicFun\n"));
}
void Dll1::privateFun()
{
OutputDebugString(_T("\nDll1--privateFun\n"));
}
重新生成后使用dumpbin命令查看确定只导出了指定的两个成员函数:
这里尝试在成员变量声明中加__declspec(dllexport) 导出声明, 会有以下提示信息:
使用导出类
对于这两种情况生成的DLL,客户端程序在访问方式上是没有区别的,都是先构造该类的一个实例对象,然后利用该对象调用成员函数.
在DLL_test项目中通过类的示例对象尝试访问私有成员:
//DLL_test项目main.cpp
#include <iostream>
using namespace std;
#include "Dll1.h"
int main()
{
Dll1 dll1;
dll1.publicFun();
dll1.privateFun();
cout << "public val: " << dll1.m_nVal << " private val: " << dll1.m_nVal2 << endl;
}
编译报错:
可以看到对于两个私有成员,同普通类一样,无法通过实例对象访问.
屏蔽后再编译:
提示Dll1的默认构造和析构是无法解析的外部符号,因为DLL1项目中并没有指定构造和析构为导出函数,这里找不到也是正常.
重新修改DLL1项目头文件代码如下:
//Dll1.h
#ifdef DLL1_API
#else
#define DLL1_API __declspec(dllimport)
#endif
//int __declspec(dllimport) add(int a, int b);
//extern int DLL1_API add(int a, int b);
//int __declspec(dllimport) subtract(int a, int b);
//extern int DLL1_API subtract(int a, int b);
class /*DLL1_API*/ Dll1
{
public:
DLL1_API Dll1();
virtual DLL1_API ~Dll1();
void DLL1_API publicFun();
public:
int /*DLL1_API*/ m_nVal;
private:
void DLL1_API privateFun();
int /*DLL1_API*/ m_nVal2;
};
源文件无需修改.
重新生成后使用dumpbin命令查看,可以看到构造和析构函数的信息:
更新lib,dll,.h头文件到DLL_test项目中,编译运行:
可以看到dll1正常构造,调用成员函数以及析构.
总结
至此,我们可以知道动态链接库导出整个类和仅导出该类的某些成员函数在实现方式上的区别:
如果在声明类时,指定了导出标志,那么该类中的所有函数都将被导出,否则只有那些声明时指定了导出标志的类成员函数才被导出.
这两种方式均不可以导出类的成员变量.