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加密,返 ...
随机推荐
- tarjan算法模板
终于能自己完整的打下来 #include<cstdio> #include<cstring> #include<iostream> #include<vect ...
- jquery 获得星期几-根据当前日期判断是星期几
jquery 获得星期几 <script type="text/javascript"> var date = "07/17/2014"; / ...
- 【Unity3D游戏开发】基础知识之Tags和Layers (三二)[转]
Tags和Layers分别表示是Unity引擎里面的标签和层,他们都是用来对GameObject进行标识的属性,Tags常用于单个GameObject,Layers常用于一组的GameObject.添 ...
- 解决HtmlAgilityPack无法获取form标签子节点的问题
问题描述 今天使用HtmlAgilityPack提取Form表单下的input节点,发现提取的form节点没有子节点,InnerHtml也是为空,起初以为是标签不全导致,后来分析html代码发现不可能 ...
- 借助Nodejs在服务端使用jQuery采集17173游戏排行信息
Nodejs相关依赖模块介绍 Nodejs的优势这里就不做介绍啦,这年头相信大家对它也不陌生了.这里主要介绍一下用到的第三方模块. async:js代码中到处都是异步回调,很多时候我们需要做同步处理, ...
- 折半查找&clock函数
#include <stdio.h>#include <time.h> #define CLOCKS_PER_SEC ((clock_t)1000) int binsearch ...
- Codeforces Round #375 (Div. 2) D. Lakes in Berland dfs
D. Lakes in Berland time limit per test 2 seconds memory limit per test 256 megabytes input standard ...
- scala打印九九乘法表的5种实现
使用scala打印九九乘法表,可以有多种实现方法,实现的过程充分的体现的scala语言的优势和巨大的简洁性和高效性, 下面我用了5种方法实现九九乘法表. 使用类似于java,c++等指令风格的的编程实 ...
- 【T-SQL系列】新的排序函数
如:ROW_NUMBER.RANK.DENSE_RANK三个分析函数都是按照col1分组内从1开始排序 ROW_NUMBER() 是没有重复值的排序(即使两天记录相等也是不重复的),可以利用它来实现分 ...
- ZOJ-3725 Painting Storages 动态规划
题意:给定一个数N,表示有N个位置,要么放置0,要么放置1,问至少存在一个连续的M个1的放置方式有多少? 分析:正面求解可能还要考虑到重复计算带来的影响,该题适应反面求解.设dp[i][j]表示到前 ...