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接口的实现(虚函数)的更多相关文章

  1. c# 基础(重写与覆盖:接口与抽象,虚函数与抽象函数)

    总结 1:不管是重写还是覆盖都不会影响父类自身的功能(废话,肯定的嘛,除非代码被改). 2:当用子类创建父类的时候,如 C1 c3 = new C2(),重写会改变父类的功能,即调用子类的功能:而覆盖 ...

  2. 24.C++- 抽象类(存虚函数)、接口、多重继承

    抽象类和接口 什么是抽象类 用来表示现实世界中的抽象概念 是一种只能定义类型,而不能产生对象的类 只能被子类继承,且抽象类的相关成员函数没有完整的体现,用来被子类重写. 比如图形(Shape)类, 就 ...

  3. Java C++ 比较 – 虚函数、抽象函数、抽象类、接口

    [转自]原文 Java – 虚函数.抽象函数.抽象类.接口 1. Java虚函数 虚函数的存在是为了多态. C++中普通成员函数加上virtual关键字就成为虚函数 Java中其实没有虚函数的概念,它 ...

  4. C++ 系列:虚函数

    Copyright © 1900-2016, NORYES, All Rights Reserved. http://www.cnblogs.com/noryes/ 欢迎转载,请保留此版权声明. -- ...

  5. C++ Primer--虚函数与纯虚函数的区别

    首先:强调一个概念 定义一个函数为虚函数,不代表函数为不被实现的函数. 定义他为虚函数是为了允许用基类的指针来调用子类的这个函数. 定义一个函数为纯虚函数,才代表函数没有被实现. 定义纯虚函数是为了实 ...

  6. C++中虚函数的作用

    一, 什么是虚函数(如果不知道虚函数为何物,但有急切的想知道,那你就应该从这里开始) 简单地说,那些被virtual关键字修饰的成员函数,就是虚函数.虚函数的作用,用专业术语来解释就是实现多态性(Po ...

  7. C++中虚函数的作用是什么?它应该怎么用呢?

    虚函数联系到多态,多态联系到继承.所以本文中都是在继承层次上做文章.没了继承,什么都没得谈. 下面是对C++的虚函数这玩意儿的理解. 一, 什么是虚函数(如果不知道虚函数为何物,但有急切的想知道,那你 ...

  8. C++中虚函数和纯虚函数的区别与总结

    首先:强调一个概念 定义一个函数为虚函数,不代表函数为不被实现的函数. 定义他为虚函数是为了允许用基类的指针来调用子类的这个函数. 定义一个函数为纯虚函数,才代表函数没有被实现. 定义纯虚函数是为了实 ...

  9. C++虚函数与纯虚函数用法与区别(转载)

    1. 虚函数和纯虚函数可以定义在同一个类(class)中,含有纯虚函数的类被称为抽象类(abstract class),而只含有虚函数的类(class)不能被称为抽象类(abstract class) ...

随机推荐

  1. Set up development environment for apps for SharePoint 2013

    SharePoint 2013 support app development pattern.An app for SharePoint is small and isolate applicati ...

  2. js 社会主义点击事件

    index.js 效果演示地址: https://www.purecss.cn/ (function() { var coreSocialistValues = ["富强", &q ...

  3. echarts legend 的单选模式以及轮播技巧

    1.设置 legend 属性: selectedMode: 'single' 2.使用 myCharts.dispatchAction 来设置legend的聚焦 broadcast (v) { // ...

  4. unity, ios skin crash

    https://issuetracker.unity3d.com/issues/ios-loading-models-with-tangents-set-to-calculate-legacy-fro ...

  5. haproxy 同一域名下分发请求

    http://www.th7.cn/Program/java/201608/936162.shtml https://my.oschina.net/lockupme/blog/733375 还有一点要 ...

  6. Java 技术新手入门

    对于想学习Java的朋友 请参考IBM旗下站点:http://www.ibm.com/developerworks/cn/java/newto/index.html 我看了下对于新手有很好的指导,并且 ...

  7. C#判断访问网站的设备类型

    同样也是在破解版的HISHOP源码上扒出来的,代码如下: protected void InitVisitorTerminal()        {            VisitorTermina ...

  8. [svc]高并发场景 LVS DR +KeepAlive高可用实现及ka的persistence_timeout参数

    LVS-DR+keepalived模式是一种非常经典的常用生产组合 高可用场景及LVS架构 一般都用一(负载)拖多(Server Array)方式 使用LVS架设的服务器集群系统有三个部分组成: (1 ...

  9. [na]ip数据包格式

    IP Datagram Structure 字段名 解释 版本 IP协议的版本,目前的IP协议版本号为4,下一代IP协议版本号为6. 首部长度 IP报头的长度.固定部分的长度(20字节)和可变部分的长 ...

  10. android源码上面开发App

    使用eclipse 打开源码:http://blog.csdn.net/androidlover1991/article/details/17011991 使用android studio 打开源码h ...