VC++导入导出类
一、导出类
VC++中导出类很简单,下面列出了两个等价的方法:
方法1:
class __declspec(dllexport) CTest
{
public:
int m_nValue;
CObj m_obj;
};
方法2:
class __declspec(dllexport) CTest; //类声明,说明是一个导出类
class CTest
{
public:
int m_nValue;
CObj m_obj;
};
注意:方法2的类声明必须放在 class CTest 的前面,最好放在预编译头文件 StdAfx.h 里。
使用方法1比较麻烦,要导出一个类还得修改类定义;方法2就比较方便了,可以将要导出的类声明集中放在 StdAfx.h 里,方便维护。
需要注意以下几个问题:
1、成员对象所属类也需要被导出
m_obj是CTest的成员对象,它所属的类CObj也需要被导出。否则编译的时候会产生警告,客户程序可能无法正常构造CTest类(Debug版正常,Release版分配内存但不调用构造函数)。如果导出CObj比较困难,如它是一个模板类,则应该将CObj m_obj更改为CObj*m_obj;
2、内联成员函数
内联函数相当于宏,编译的时候用来替换源代码,用以提高效率。一般它是不会被编译成目标代码的,但是一旦使用了__declspec(dllexport),编译程序将会为其生成一份目标代码,客户程序调用内联成员函数时,可能直接调用目标代码,此时函数将不再是内联的了。当然,导入类时也可以控制客户程序,使其使用内联的成员函数。
3、友元函数
需要注意的是,上述两个方法均不能导出类的友元函数。要导出友元函数,必须专门声明。方法1、2的改进方案为:
方法1:
class __declspec(dllexport) CTest
{
public:
int m_nValue;
public:
//导出友元函数要专门声明
friend __declspec(dllexport) CTest operator+(const CTest&a,const CTest&b);
};
方法2:
class __declspec(dllexport) CTest;
//导出友元函数要专门声明
__declspec(dllexport) CTest operator+(const CTest&a,const CTest&b);
class CTest
{
public:
int m_nValue;
public:
friend CTest operator+(const CTest&a,const CTest&b);
};
4、嵌套类
要导出嵌套类,方法1的改进方案为:
class __declspec(dllexport) CTest
{
public:
class __declspec(dllexport) CNest //前面也要使用__declspec(dllexport)
{
}
};
方法2无法导出嵌套类,因为不能按下面的语法进行嵌套类声明:
class __declspec(dllexport) CTest::CNest; //这样声明是错误的
此时,解决方案可能只有使用DEF文件了。
二、使用DEF文件导出类
按下图设置,使得编译时生成map文件。

编译如下代码
class __declspec(dllexport) CTest
{
public:
void SetValue(int v) {m_Value = v;}
int GetValue();
private:
int m_Value;
public:
static int s_nValue;
};
int CTest::s_nValue = 1;
int CTest::GetValue() {return m_Value;}
查看 map 文件,提取包含 CTest 的函数或变量:
|
Address |
Publics by Value |
Rva+Base |
Lib:Object |
|
0001:00000030 |
?SetValue@CTest@@QAEXH@Z |
10001030 f i |
tDLL.obj |
|
0001:00000070 |
??4CTest@@QAEAAV0@ABV0@@Z |
10001070 f i |
tDLL.obj |
|
0001:000000b0 |
?GetValue@CTest@@QAEHXZ |
100010b0 f |
tDLL.obj |
|
0003:00000a30 |
?s_nValue@CTest@@2HA |
1002ba30 |
tDLL.obj |
注意上表的第三列,f表示函数,i表示内联。如果将 class __declspec(dllexport) CTest 中的 __declspec(dllexport) 去掉,重新编译,则上表第三列包含 f i 的在map文件中不会再出现。
内联函数没有目标代码,所以无法通过 DEF 导出。只能通过DEF文件导出非内联的成员函数,如:下面的DEF文件内容导出了CTest::GetValue函数。
EXPORTS
?GetValue@CTest@@QAEHXZ
?s_nValue@CTest@@2HA对应着CTest::s_nValue,它应该被导出,但是使用DEF导出变量需要注意:客户程序导入该变量时,只能导入该变量的地址。
三、导入类
导出类到动态链接库的同时,就生成了库文件(*.lib)。VC++很智能,客户程序包含这个库文件即可完成类的导入。要特别注意这种导入的内联成员函数。下面的代码中,客户程序调用内联成员函数GetValue时,将不会使用导出类的GetValue目标代码,而是使用类声明中的代码。此时,GetValue还是内联函数。
class CTest
{
public:
int m_nValue;
public:
int GetValue()
{
return m_nValue;
}
};
如果不想客户程序使用类声明中的代码,有两种方法:
1、删除内联函数GetValue的实现代码,仅仅保留函数声明;
2、使用__declspec(dllimport),如下所示:
class __declspec(dllimport) CTest
{
public:
int m_nValue;
public:
int GetValue()
{
return m_nValue;
}
};
或在 StdAfx.h 中,增加class __declspec(dllimport) CTest;这句类声明。使用__declspec(dllimport)声明类之后,友元函数就不再需要__declspec(dllimport)声明了。
四、总结
1、导出类有两种方法,一种是使用 __declspec(dllexport);另一种方法是使用DEF文件,该方法不能导出内联函数,导出类的静态成员变量也较为不便;
2、友元函数不属于类,要导出的话必须使用 __declspec(dllexport) 声明,或在 DEF 文件中导出;
3、导入类可以使用 __declspec(dllimport),也可以不使用。前者将取消内联成员函数的内联性质,后者不会;
应用实例:
下面是类CTest的定义部分,在 Test.h 里
class CTest
{
public:
class CNest
{
public:
void SetValue(int v);
int GetValue();
friend CNest operator+(const CNest&a,const CNest&b);
private:
int m_nValue;
};
public:
void SetValue(int v);
int GetValue();
friend CTest operator+(const CTest&a,const CTest&b);
private:
int m_nValue;
public:
static int s_nValue;
};
下面是类CTest的实现部分,在Test.cpp里
//CTest-------------------------------------------------------------------------
int CTest::s_nValue = 1;
void CTest::SetValue(int v)
{
m_nValue = v;
}
int CTest::GetValue()
{
return m_nValue;
}
CTest operator+(const CTest&a,const CTest&b)
{
CTest c;
c.m_nValue = a.m_nValue + b.m_nValue;
return c;
}
//CTest::CNest------------------------------------------------------------------
void CTest::CNest::SetValue(int v)
{
m_nValue = v;
}
int CTest::CNest::GetValue()
{
return m_nValue;
}
CTest::CNest operator+(const CTest::CNest&a,const CTest::CNest&b)
{
CTest::CNest c;
c.m_nValue = a.m_nValue + b.m_nValue;
return c;
}
导出 CTest 类及其友元函数,只需在 StdAfx.h 里增加如下代码:
class __declspec(dllexport) CTest;
__declspec(dllexport) CTest operator+(const CTest&a,const CTest&b);
导出CTest::CNest的成员函数稍微麻烦些,需要在DEF文件中导出:
EXPORTS
?SetValue@CNest@CTest@@QAEXH@Z
?GetValue@CNest@CTest@@QAEHXZ
??H@YA?AVCNest@CTest@@ABV01@0@Z
客户程序导入CTest类,只需在 StdAfx.h 里增加如下代码:
class __declspec(dllimport) CTest;
//有了上面的声明,CTest的友元函数就不再需要特别声明了
//下面这句话反而会引起警告
__declspec(dllimport) CTest operator+(const CTest&a,const CTest&b);
客户程序对 CTest::CNest 的导入无需特别声明,VC++编译器能够自动完成。但是,它对CNest是有限制的,即不能有静态成员变量。如果有,最好的办法就是不要使用嵌套了。
VC++导入导出类的更多相关文章
- MinGW dll导入导出类
dll不仅可以导入导出函数,还可以导入导出类.这篇文章就来介绍如何将类导入dll中并导出. 首先我们建立一个名为dll.cpp的文件(又是这种破名字),里面写上: #include <iostr ...
- 不依赖Excel是否安装的Excel导入导出类
本文利用第三方开源库NPOI实现Excel97-2003,Excel2007+的数据导入导出操作. 不依赖Office是否安装.NPOI开源项目地址:http://npoi.codeplex.com/ ...
- .net core 基于NPOI 的excel导入导出类,支持自定义导出哪些字段,和判断导入是否有失败的记录
#region 从Excel导入 //用法 //var cellHeader = new Dictionary<string, string>(); //cellHeader.Add(&q ...
- C++ DLL导出类 知识大全
在公司使用C++ 做开发,公司的大拿搭了一个C++的跨平台开发框架.在C++开发领域我还是个新手,有很多知识要学,比如Dll库的开发. 参考了很多这方面的资料,对DLL有一个基本全面的了解.有一个问题 ...
- 导入导出Excel工具类ExcelUtil
前言 前段时间做的分布式集成平台项目中,许多模块都用到了导入导出Excel的功能,于是决定封装一个ExcelUtil类,专门用来处理Excel的导入和导出 本项目的持久化层用的是JPA(底层用hibe ...
- NPOI导入导出EXCEL通用类,供参考,可直接使用在WinForm项目中
以下是NPOI导入导出EXCEL通用类,是在别人的代码上进行优化的,兼容xls与xlsx文件格式,供参考,可直接使用在WinForm项目中,由于XSSFWorkbook类型的Write方法限制,Wri ...
- 022医疗项目-模块二:药品目录的导入导出-对XSSF导出excel类进行封装
资源全部来源于传智播客. 好的架构师写的程序,就算给刚入门的新手看,新手一看就知道怎么去用.所以我们要对XSSF导出excel类进行封装.这是架构师的工作,但我们也要知道. 我们写一个封装类: 这个类 ...
- 021医疗项目-模块二:药品目录的导入导出-介绍poi类
我们使用的是.10版本 Apache POI - the Java API for Microsoft Documents,Apache POI 是用Java编写的免费开源的跨平台的 Java API ...
- ASP.NET 之 常用类、方法的超级总结,并包含动态的EXCEL导入导出功能,奉上类库源码
实用类:UtilityClass 包含如下方法 判断对象是否为空或NULL,如果是空或NULL返回true,否则返回false 验证手机号是否正确 13,15,18 验证邮箱 验证网址 MD5加密,返 ...
随机推荐
- Android 客户端应用开发的架构
本文算是一篇漫谈,谈一谈关于android开发中工程初始化的时候如何在初期我们就能搭建一个好的架构.关于android架构,因为手机的限制,目前我觉得也确实没什么大谈特谈的,但是从开发的角度,看到整齐 ...
- ASCII字符表
- 解决maven的“Dynamic Web Module 3.0 requires Java 1.6 or newer.”错误
需要添加一个插件,在build标签中添加 <plugins> <plugin> <groupId>org.apache.maven.plugins</grou ...
- Infragistics 汉化
Infragistics 汉化实例: Infragistics.Shared.ResourceCustomizer rc=Infragistics.Win.UltraWinGrid.Resources ...
- Monkey类、People类和主类 E。
package jicheng; public class Monkey { private String s; public String getS() { return s; } public v ...
- C#日志写入
/// <summary> /// 写日志,指定日志文件 /// </summary> /// <param name="File"></ ...
- Know How To Use Check Box Mapping Of Other Values Property In Oracle Forms
Check Box Mapping of Other Values specifies how any fetched or assigned value that is not one of the ...
- Linux运行变量中的命名脚本
single="ls -l" $single ============= multi="ls -l | grep e" echo $multi > tmp ...
- 观摩制作小游戏(js应用)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- NPOI大数据分批写入同个Excel
实现过程: 要导出来的数据库数据量很大,一次取出来压力有点大,故分批取出来,导入到同一个Excel. 因为Excel2003版最大行数是65536行,Excel2007开始的版本最大行数是104857 ...