DLL接口的实现(虚函数)
DLL接口的实现(虚函数)
我们在c++编程过程中往往要用到各种不同形式的程序库,这些库的发布方式有动态库和静态库。对于静态类库,设计良好的静态类库能实现功能上的隔离,无法避免类库实现必须重新编译、链接整个应用程序的问题。而调用各种DLL动态库成为我们程序员的家常便饭。
以什么方式暴露库的接口?可选的做法有:以全局(含 namespace 级别)函数为接口、以 class 的 non-virtual 成员函数为接口、以 virtual 函数为接口(interface)。本文主要讲虚函数实现DLL接口和COM组件。
虚函数实现接口的做法是定义一个头文件,将类实现的接口声明,可以将这个类的成员函数暴露给客户。而接口的实现部分是在派生类中,用户获得头文件中的接口,无需接口的实现就可以调用接口。往往我们会将这个接口类的成员定义为纯虚函数,这样更直观的体现派生类必须完成对接口的实现部分。
以下是代码实例:
接口头文件 IPerson.h
#include<iostream>
#include<string>
using namespace std; #ifdef _EXPORTING
#define CLASS_DECLSPEC __declspec(dllexport)
#else
#define CLASS_DECLSPEC __declspec(dllimport)
#endif class IPerson
{
public:
IPerson(){}; //接口
virtual void SetName(const string &strName) = 0;
virtual const string GetName() = 0;
virtual void Work() = 0;
};
declspec(dllexport)用于导出符号,也就是定义该函数的dll;__declspec(dllimport)用于导入,也就是使用该函数。因为这个头文件既要被定义该函数的dll包含,也要被使用该函数的程序包含,当被前者包含时我们希望使用__declspec(dllexport)定义函数,当被后者包含时我们希望使用dllimport。于是我们使用
#ifdef _EXPORTING
#define CLASS_DECLSPEC __declspec(dllexport)
#else
#define CLASS_DECLSPEC __declspec(dllimport)
#endif
这种技巧,在定义该函数的dll中,其编译选项定义了_EXPORTING而使用该函数的程序则没有定义。反正我们的头文件是要暴露给用户的,这样定义可以保持DLL库头文件和用户库头文件保持一致。
接口实现部分:CTeacher.cpp
#include "IPerson.h" //定义接口
CLASS_DECLSPEC bool GetIPersonObject(void** _RtObject); class CTeacher:public IPerson
{
public:
CTeacher(){}
//接口实现
void SetName(const string &strName);
const string GetName();
void Work();
private:
string m_strName;
}; void CTeacher::SetName(const string &strName)
{
m_strName = strName;
}
const string CTeacher::GetName()
{
return m_strName;
}
void CTeacher::Work()
{
cout<<"I am teaching!"<<endl;
} bool GetIPersonObject(void **_RtObject)
{
IPerson* pMan = NULL;
pMan = new CTeacher();
*_RtObject = (void*)pMan;
return true;
}
这样,我们在工程->属性->配置属性->常规->配置类型 中选择 动态库(.dll)运行就可以生成对应的.dll和.lib。我们在客户程序中就可以使用这个dll。具体做法如下:1.程序中包含接口的头文件,即 IPerson.h 2.包含lib,在 工程->属性->配置属性->VC++目录->库目录中加入.lib的文件目录,在工程->属性->配置属性->连接器->输入->附加依赖项中加入.lib 。
#include "IPerson.h" #pragma comment(lib,"InterFace.lib") //导出接口
bool CLASS_DECLSPEC GetIPersonObject(void** _RtObject); void main()
{
IPerson * _IPersonObj = NULL;
void* pObj=NULL;
if (GetIPersonObject(&pObj))
{
// 获取对象
_IPersonObj = (IPerson *)pObj;
// 调用接口,执行操作
_IPersonObj->SetName("Tom");
string strName = _IPersonObj->GetName();
_IPersonObj->Work();
}
if (_IPersonObj !=NULL)
{
delete _IPersonObj ;
_IPersonObj = NULL;
}
}
到这里,一个简单的虚函数实现DLL接口就做完了。有一点必须要说,设计库的时候C++ 虚函数为接口是有弊端的。“一旦发布,不能修改”。a)函数重名问题:我们通过函数名来调用DLL的函数,在并行开发中 容易造成函数重名。b)依赖:如果采用常见的隐式连接,那DLL每发行了一个新版本都有 必要和应用程重新链接一次,因为DLL里面函数的地址可能已经发生了改变。
COM组件的思想正好解决了上述问题,下一节讲COM组件思想的简单实现。
https://blog.csdn.net/u011599942/article/details/11195667
DLL接口的实现(虚函数)的更多相关文章
- c# 基础(重写与覆盖:接口与抽象,虚函数与抽象函数)
总结 1:不管是重写还是覆盖都不会影响父类自身的功能(废话,肯定的嘛,除非代码被改). 2:当用子类创建父类的时候,如 C1 c3 = new C2(),重写会改变父类的功能,即调用子类的功能:而覆盖 ...
- 24.C++- 抽象类(存虚函数)、接口、多重继承
抽象类和接口 什么是抽象类 用来表示现实世界中的抽象概念 是一种只能定义类型,而不能产生对象的类 只能被子类继承,且抽象类的相关成员函数没有完整的体现,用来被子类重写. 比如图形(Shape)类, 就 ...
- Java C++ 比较 – 虚函数、抽象函数、抽象类、接口
[转自]原文 Java – 虚函数.抽象函数.抽象类.接口 1. Java虚函数 虚函数的存在是为了多态. C++中普通成员函数加上virtual关键字就成为虚函数 Java中其实没有虚函数的概念,它 ...
- C++ 系列:虚函数
Copyright © 1900-2016, NORYES, All Rights Reserved. http://www.cnblogs.com/noryes/ 欢迎转载,请保留此版权声明. -- ...
- C++ Primer--虚函数与纯虚函数的区别
首先:强调一个概念 定义一个函数为虚函数,不代表函数为不被实现的函数. 定义他为虚函数是为了允许用基类的指针来调用子类的这个函数. 定义一个函数为纯虚函数,才代表函数没有被实现. 定义纯虚函数是为了实 ...
- C++中虚函数的作用
一, 什么是虚函数(如果不知道虚函数为何物,但有急切的想知道,那你就应该从这里开始) 简单地说,那些被virtual关键字修饰的成员函数,就是虚函数.虚函数的作用,用专业术语来解释就是实现多态性(Po ...
- C++中虚函数的作用是什么?它应该怎么用呢?
虚函数联系到多态,多态联系到继承.所以本文中都是在继承层次上做文章.没了继承,什么都没得谈. 下面是对C++的虚函数这玩意儿的理解. 一, 什么是虚函数(如果不知道虚函数为何物,但有急切的想知道,那你 ...
- C++中虚函数和纯虚函数的区别与总结
首先:强调一个概念 定义一个函数为虚函数,不代表函数为不被实现的函数. 定义他为虚函数是为了允许用基类的指针来调用子类的这个函数. 定义一个函数为纯虚函数,才代表函数没有被实现. 定义纯虚函数是为了实 ...
- C++虚函数与纯虚函数用法与区别(转载)
1. 虚函数和纯虚函数可以定义在同一个类(class)中,含有纯虚函数的类被称为抽象类(abstract class),而只含有虚函数的类(class)不能被称为抽象类(abstract class) ...
随机推荐
- 【转】TeXmacs:一个真正“所见即所得”的排版系统
TeXmacs:一个真正“所见即所得”的排版系统 好久没有推荐过自己喜欢的软件了,现在推荐一款我在美国做数学作业的私家法宝:TeXmacs.我恐怕不可能跟以前那么有闲心写个长篇的 TeXmacs 说明 ...
- Java 内存溢出思维导图
文 by / 林本托 Tips 做一个终身学习的人. 在 Java 内存中,只有一个区域不会发生 OOM 异常,那就是程序计数器内存.下面的思维导图记录了每个内存区域发生内存异常的条件和基本的解决思路 ...
- MySql 按周/月/日统计数据的方法
知识关键词:DATE_FORMAT select DATE_FORMAT(create_time,'%Y%u') weeks,count(caseid) count from tc_case gro ...
- sqlserver数据库18456错误怎么解决?
1.以windows验证模式进入数据库管理器. 2.右击sa,选择属性: 在常规选项卡中,重新填写密码和确认密码(改成个好记的).把强制实施密码策略去掉. 3.点击状态选项卡:勾选授予和启用.然后确定 ...
- php分享三十:php版本选择
思考: cgi是怎么运行的?(是多线程?多进程?单线程?单进程?) fastcgi运行原理? apache运行php的原理? (是多进程还是多线程?) nginx是怎么运行php的? 什么是安全模式和 ...
- MySQL与Oracle的区别之我见
1. 大的方面(宏观) Oracle为商用数据库,行业中占据相当的地位:市场占比2012年为40%.开发.管理资源相当丰富,有自己的metalink,我也曾用过,有什么问题,都能在那里得到较快速度的解 ...
- Bug:java.lang.StackOverflowError: stack size 8MB
在开发的时候遇到了这个Bug:java.lang.StackOverflowError: stack size 8MB Log: 11-27 14:16:37.093 21892-21892/com. ...
- 译: 3. Axis2快速入门指南
本指南的目的是让您尽快使用Axis2开始创建服务和客户端.我们将采用一个简单的StockQuote服务,向您展示可以创建和部署它的一些不同方式,以及快速查看Axis2附带的一个或两个实用程序.然后,我 ...
- 顺时针旋转打印n阶矩阵(内测第0届第4题)
题目要求 问题描述:顺时针旋转打印n阶矩阵 样例输入:4 1 2 3 4 12 13 14 5 11 16 15 6 10 9 8 7 样例输出:1 2 ...
- Chunk
Chunk是一系列语句,Lua执行的每一块语句,比如一个文件或者交互模式下的每一行都是一个Chunk. 每个语句结尾的分号(;)是可选的,但如果同一行有多个语句最好用:分开 a = 1 b = a ...