Balon白话MSDN:从普通DLL中导出C++类(2) – 细看导出C++类的底层机制

Balon白话MSDN:从普通DLL中导出C++类(1) – dllexport和dllimport的使用方法(中英对照、附注解)  Balon白话MSDN:从普通DLL中导出C++类(1) – dllexport和dllimport的使用方法(中英对照、附注解)这几天写几个小程序练手,在准备将一个类导出时,发现还真不知道如果不用MFC的扩展DLL,是怎么导出的。但我知道dllexport可以导出函数和变量,而且MFC扩展DLL就算是使用了MFC的功能,但能否导出类应该也不是必须用MFC才能够做到,一定是有相应的机制可 阅读详情

 

Balon白话MSDN:从普通DLL中导出C++类(2) – 细看导出C++类的底层机制
上一篇文章中,我们介绍了怎么从一个DLL中导出C++类,及选择性导出C++类的成员的方法。那么,整个系统的底层机制是怎么样的?是通过什么途径,使得我们可以在另一个程序中使用一个DLL中导出的类的呢?
我们知道,要使用一个C++类,必要的条件是在编译期能得到这个类的头文件,并在链接期可以找到对应的符号的链接地址(比如成员函数、静态数据成员等)。如果这个C++类与你的使用者在同一个工程,那这个条件很好满足:
首先,C++类的头文件很好获得。直接在使用者那里将类的头文件include即可
其次,C++类往往被编译器作为一个编译单元,生成一个obj文件。在最后进行链接的过程中,链接器会把工程中所有的obj链接以生成最终的二进制目标文件。所以链接器在遇到一处对类成员函数(或其它形式的符号引用)时,会在这个类生成的obj文件中找到符号的链接地址。
那么,在代码中使用一个C++类,编译期和链接期需要的到底是些什么东西呢?换句话说,满足了什么样的条件,编译器和链接器就不会抱怨了呢?
根据C++语言的定义,一个C++类实际上是声明或定义了如下几类内容:
1.    声明了一个数据结构,类中的非静态数据成员、代码中看不到但如果有虚函数就会生成的虚表入口地址指针等。
2.    声明并定义了一堆函数,它们第一个参数都是一个指向这个数据结构的指针。这些实际上就是类中那些非静态成员函数(包括虚函数),它们虽然在类声明中是写在类的一对大括号内部,但实际上没有任何东西被加到前面第1条中所说的内部数据结构中。实际上,这样的声明只是为这些函数增加了两个属性:函数名标识符的作用域被限制在类中;函数第一个参数是this,被省略不写了。
3.    声明并定义了另一堆函数,它们看上去就是一些普通函数,与这个类几乎没有关系。这些实际上就是类中那些静态函数,它们也是一样,不会在第1条中所说的内部数据结构中增加什么东西,只是函数名标识符的作用域被限制在类中。
4.    声明并定义了一堆全局变量。这些实际上就是类中那些静态数据成员。
5.    声明并定义了一个全局变量,此全局变量是一个函数指针数组,用来保存此类中所有的虚函数的入口地址。当然,这个全局变量生成的前提是这个类有虚函数。
下面是一个例子。
class  MyClass
{
public :
    
int  x;
    
int  y;
    
void  Foo();
    
void  Bar( int  newX,  int  newY);
    
virtual   void  VFoo();
    
virtual   void  VBar( int  newX,  int  newY)  =   0 ;
    
static   void  SFoo();
    
static   void  SBar( int  newX,  int  newY);
    
static   int  sx;
    
static   int  sy;
};
对于上面列出的这个类MyClass,C++编译器多数会以如下的方式进行编译:
编译器生成的类的二进制结构
现在我们再来看一下为什么编译器需要头文件和符号地址就可以编译链接一个使用MyClass的程序了。
首先,由于编译器需要在编译期就知道类的内存布局,以保证可以生成正确的开辟内存的代码,及那些sizeof(MyClass)的值。有了头文件,编译器就知道,一个MyClass占用12字节的内存空间(见上图,两个整数和一个指针)。
其次,在调用MyClass的成员函数、静态函数时,链接器需要知道这些函数的入口地址,如果无法提供入口地址,链接器就会报错。
最后,在引用MyClass的静态数据成员时,实际上与引用一个外部全局对象一样,链接器需要知道这些变量的地址。如果无法提供这些变量的地址,链接器也会报错。
可以看出:
1.    编译期:必须要提供的是类的头文件,以使编译器可以得知类实例的尺寸和内存布局。
2.    链接期:必须要提供的是程序中引用过的,类的成员函数、静态函数、静态数据成员的地址,以使链接器可以正确的生成最终程序。
到这里,我们可以猜到,实际上,导出一个类,编译器实际上只需要将这个类中的:成员函数、静态函数、静态数据成员当成普通的函数、全局变量导出即可。也就是说,我们实际上没有“导出一个类”,而是把这个类中需要被引用的“有定义的实体”的入口地址像普通函数和变量那样正常导出即可。
最后我们来看一下,实际上生成的一个导出前面列的的那个MyClass类的DLL。用Dependence来查看,可以看到下面的结果:
用dependence察看生成的DLL的结果
可以看到,除了VBar函数是一个纯虚函数外,其它函数、静态数据成员的入口地址都被导出。另外可以看到,vtable也被导出,以便操作虚函数时引用。
我写这些内容时偷了个懒,避开了虚表的一大堆复杂内容。谢谢houdy的提示,他的文章对于虚表,以及从DLL导出虚表的底层机制进行了详细的剖析,想对此刨根问底的同学一定要看下:
C++开发基础之创建DLL的常见的6种导出函数(Export Functions)形式 Windows将函数声明和定义分开,使用 __declspec(dllexport) 修饰定义 阅读详情

相关推荐

C++ DLL 导出类 示例

一个简单的C++生成DLL(导出类),然后用控制台程序去调用它的示例,可以帮助你理解如何从DLL中导出类,并使用该类。 该项使用VS2010编译,低版本可能无法打开。

如何从DLL中导出C++类及接口

 本文粘贴自 CodeProject - HowTo-Export-C-classes-from-a-DLL 。ContentsIntroductionC Language ApproachHandlesCalling ConventionsException SafetyAdvantagesDisadvantagesC++ Naive Approach: Exporting a ClassWha...

weixin_37937630的博客 1768

C++ dll隐式加载函数和类,显示加载函数和类,嵌套加载函数和类,

C++,如何调用其他动态库中的函数或类成员函数?由隐式加载和显示加载,还有嵌套加载,嵌套加载即调用的dll中还调用了其他dll,麻烦但原理一样,故没写。 注:请打开build文件夹下的sln文件,打开src下的sln文件相对路径不对会报错的。

Export from a DLL Using __declspec(dllexport)

You can export data, functions, classes, or class member functions from a DLL by using the __declspec(dllexport) keyword. If you use __declspec(dllexport), you do not need a .DEF file for exports.

Coder_LCB的博客 522

【算法】—前缀和与差分详解

前缀和指一个数组的某下标之前的所有数组元素的和(即数列的前n项求和),前缀和是一种重要的预处理,能够降低算法的时间复杂度,可以快速地求出某一段的和,对于处理区间之间的问题是往往十分高效相比较其他算法而言,前缀和更像是一种解题的技巧,一种优化方式输入一个长度为 n 的整数序列。接下来再输入 m 个询问,每个询问输入一对 l,r 对于每个询问,输出原序列中从第 l 个数到第 r 个数的和5 32 1 3 6 41 21 32 4123453610。

DAY I 的成长之路 6023

STM8开发环境搭建(STVD + COSMIC)

一、STM8开发IDE 1. STVD + COSMIC ST Visual Develop (STVD)只支持汇编开发,C语言开发需要再安装COSMIC,配套起来使用。 2. IAR IAR也可以用来开发STM8 下面介绍STVD + COSMIC的搭建方式 二、环境搭建 1. STVD下载、安装 直接从官网下载:https://www.st.com/en/development-tools/stvd-stm8.html 安装很简单,基本下一步往下点。 2. COSMIC下载、安装 对于stm8可以使用3

a183635870的博客 1万+

C++技巧(用DEF文件从DLL中导出C++类)

用DEF从DLL导出一个函数,或用__declspec(dlleXPort)指令从DLL中导出一类,想必大家已经很熟悉了,也经常使用着。这里向大家介绍一种用DEF文件从DLL导出一个类的方法。具体原理或为什么就不废话了,学会导出后,再慢慢回味吧。这里主要叙述操作步骤。 1.打开VC6.0,新建一个"Win32 Dynamic-Link Library"工程,假设叫DefClass,在“Dll k

痞子龙3D编程 2396

Windows 10/11蓝屏急救:SECURE_PCI_CONFIG_SPACE_ACCESS_VIOLATION报错全攻略(附安全模式+CMD修复)

本文针对Windows 10/11系统常见的SECURE_PCI_CONFIG_SPACE_ACCESS_VIOLATION蓝屏报错,提供了从诊断到修复的完整解决方案。文章深入剖析了该错误与系统安全功能“内存完整性”及pci.sys驱动的关系,并详细指导用户如何通过安全模式进行基础修复,以及使用命令提示符执行高级系统文件修复和注册表修改,帮助用户彻底解决蓝屏问题并恢复系统稳定。

echo99的专栏 969

Exporting a C++ class from a DLL

Adding a simple working example for exporting a C++ class from a DLL : The given below example gives you only a short overview of how dll and exe can interact each other (self explanatory ) but it needs more things to add for changing into a production co

VMLINUZ的专栏 340

ELK 企业级日志分析系统(1)

ELK平台是一套完整的日志集中处理解决方案,将、Logstash和Kiabana三个开源工具配合使用, 完成更强大的用户对日志的查询、排序、统计需求。ElasticSearch:是基于Lucene(一个全文检索引擎的架构)开发的分布式存储检索引擎,用来存储各类日志。Elasticsearch 是用 Java 开发的,可通过 RESTful Web 接口,让用户可以通过浏览器与 Elasticsearch 通信。

云计算运维工程师的成长之路 1864

保姆级教程:在mmdetection中手动计算并可视化P、R、F1值(附完整代码)

本文提供了一份详细的mmdetection教程,指导开发者如何手动计算并可视化精确率(P)、召回率(R)和F1值。通过完整的代码示例和清晰的步骤说明,帮助用户深入理解目标检测模型的性能评估方法,特别适合需要精细分析模型表现的计算机视觉研究人员和工程师。

weixin_29038303的博客 401

dll导出类比较好的方式

看了篇好文,dll导出类的,之前已经胡乱写,以后可以参考这个规范 前言/引用 转自:编写DLL所学所思(2)——导出类 参考:HowTo: Export C++ classes from a DLL 这种方式是比较合适的,跟com类似。结构是这样的: 导出类是一个派生类,派生自一个抽象类——都是纯虚函数。使用者需要知道这个抽象类的结构。DLL最少只需要提供一个用于获取类对象指...

不经一番寒彻骨,怎得梅花扑鼻香。 6032

Vue2 - 详细实现安装西瓜视频 xgplayer 插件详细配置及使用教程,利用西瓜视频播放器播放 mp4、flv、hls 格式视频文件及视频推流(直播或监控摄像头画面),支持移动端H5及PC网站!

vue2,nuxt2,西瓜视频,xgplayer,插件组件,xgplayer-hls,xgplayer-flv,xgplayer-mp4,播放视频点播和直播视频流,自定义播放器样式,截屏,监控视频,vue使用西瓜播放器播放flv、hls、mp4视频,截屏按钮,直播流,报错,黑屏,加载失败,苹果ios不兼容,重连,怎么改样式,很卡,详细教程,监控实时播放推流,倍速播放,在线flv在线推流地址,HLS播放,vue西瓜播放器,vue如何使用西瓜视频插件做直播推流回流,视频点播,flv在线视频流播放,截图功能,利用

🏆 前端领域优质创作者 1万+

dll 导出函数名的那些事

关键字: VC++  DLL 导出函数  经常使用VC6的Dependency查看DLL导出函数的名字,会发现有DLL导出函数的名字有时大不相同,导致不同的原因大多是和编译DLL时候指定DLL导出函数的界定符有关系。 VC++支持两种语言:即C/C++,这也是造成DLL导出函数差异的根源 我们用VS2008新建个DLL工程,工程名为“TestDLL” 把默认的源文件后缀 ...

dbtr55989的博客 484

小梅哥Xilinx ZYNQ学习笔记2——38译码器

译码器(Decoder)是一种多输入多输出的组合逻辑电路,负责将二进制代码翻译为特定的对象(如逻辑电平等),功能与编码器相反。译码器一般分为通用译码器和数字显示译码器两大类。本设计的是通用译码器。三八译码器,即是 3 种输入状态翻译成 8 种输出状态。1.case开始开始,endcase结束;2.数字声明时,合法的基数格式有 4 中,包括:十进制('d 或 'D),十六进制('h 或 'H),二进制('b 或 'B),八进制('o 或 'O)。数值可指明位宽,也可不指明位宽。

m0_51430584的博客 1636

企业如何开展BI建设--指标体系建设

很多企业的数字化转型工作都是从做BI项目开始的,很多企业认为,BI就是做指标大屏,所以做了很多的驾驶舱,也做了很多指标,有从系统取的,有手工填报的,甚至手工填报的比例占到了70%,最终BI沦为了填报系统,业务认为BI就是把从线下的微信沟通转到了线上录入展示,并没有给业务代来任何提升,久而久之,BI大屏就没人关心,公司高层也认为数据都是填报的,都经过了加工处理,这种数据不可信,不能反映业务开展的实际。其实在BI系统建设之前,我们首先要做的就是要梳理企业的指标,到底我们要展示哪些指标?

263

How to call c++ exported method and classes in c#

相对于C++来说,C#是个newcomer,C#提供了一些非常cool的功能,使得我们的工作更加容易。但是,在这个组件横行的年代,如果不懂利用别人写好的代码,就有点落伍了。在C++横行江湖的日子里,留下了很多功能强大的代码,探讨如何在C#的程序中使用这些代码是非常有趣也很有意义的事情,这也是我们今天这篇文章的主题。  C#是managed code,而C++不是,他们之间的几种交互方式可以用下图表

RedRiver专栏 4992

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

写C++ DLL时需要写的外部接口头文件

#ifndef WAVELET2D_H #define WAVELET2D_H #include #include using namespace std;       //the dll exports #if defined WAVE_EXPORT #define EXPORT __declspec(dllexport) #else #define EXPORT __

野狼位位的博客 3497

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

DLL导出函数名

今天想调用一个dll,GetProcAddress返回值总是Null,通过GetLastError,推断是从DLL中找不到函数名,但是函数名明明是正确的,所以查到了以下资料,以供学习。 经常使用VC6的Dependency查看DLL导出函数的名字,会发现有DLL导出函数的名字有时大不相同,导致不同的原因大多是和编译DLL时候指定DLL导出函数的界定符有关系。 VC++支持两

circle的专栏 2061

从dll中导出c++类

简介: 动态库(DLL)从开始就作为windows平台的组成部分而存在。它以独立的模块把c函数封装起来供其他用户使用 。DLL从开始就是以封装C语言的形式而存在,当然现在你也可以封装其他语言,比如c++,而如果要实现跨平台使用DLL,则我们必须回归到C语言。 利用C语言接口并不意味着我们必须丢弃掉面向对象方法。C语言可以实现应用二进制接口(ABI),这样使调用者和被调用着可以遵从统一的标准,但

hustshi的专栏 7851

VC++动态链接库(DLL)编程深入浅出(zz)

1.概论  先来阐述一下DLL(Dynamic Linkable Library)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用的变量、函数或类。在仓库的发展史上经历了“无库-静态链接库-动态链接库”的时代。  静态链接库与动态链接库都是共享代码的方式,如果采用静态链接库,则无论你愿不愿意,lib中的指令都被直接包含在最终生成的EXE文件中了。但是若使用DLL,该DLL不必...

weixin_33755554的博客 641

C++ DLL导出类

C++ DLL导出类 http://blog.youkuaiyun.com/jietoulangren/article/details/14052533 在公司使用C++ 做开发,公司的大拿搭了一个C++的跨平台开发框架。在C++开发领域我还是个新手,有很多知识要学,比如Dll库的开发。    参考了很多这方面的资料,对DLL有一个基本全面的了解。有一个问题让我有点困惑,普通的导入导出C++类的方式

优快云Microsoft优快云的专栏 4777
上一篇: Balon白话MSDN:从普通DLL中导出C++类(1) – dllexport和dllimport的使用方法(中英对照、附注解)
下一篇: DayDayUp - CUDA、GPGPU,GPU通用计算技术
BalonFan
博客等级 码龄26年 47粉丝 41原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值