C++ dll 学习记录

一直做伸手党,有问题基本就是google和度娘,平时也很懒惰,水平一般,是时候静心,学学知识,写写博客,当然,菜鸟写不出什么东西,权当自己的日记了。万一写错了,看到的朋友切勿人参公鸡啊。写出来的东西,全部是平时遇到的问题,当然都是google或者度娘来的,但是文字或者代码都是
自己撸出来的,唉,还有自己的表达能力太差了,有时候心里明白的东西,到嘴边了,就是说不清楚,废话不说了。。。

参加工作后,第一份开发的工作是windows方面的开发,首先接触到的是COM组件的开发,那最基本的还是要学习DLL的基本知识。就是DLL里的函数如果要被外部调用,都要声明为导出函数。当然还可以导出类,外部用户调用这个类,这个类也是需要声明导出类.现在我的动态库里是这样一种情况,dll里导出一个接口,getCar用来获得dll内部类的一个指针(实例代码,且暂不考虑dll里指针内存释放的问题),内部有一个CCar的类,封装了很多功能,通过导出函数来获取这个类的一个实例,但是这个内部类也要申明为导出类,否则回报链接错误,实例代码如下:

dll里的头文件

// MYDLL_API 函数视为是从 DLL 导入的,而此 DLL 则将用此宏定义的
// 符号视为是被导出的。
#ifdef MYDLL_EXPORTS
#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllimport)
#endif

//dll 内部定义的一个类,封装实现功能
class CCar
{
public:
    CCar();
    ~CCar();
    void Run();
};

//导出的函数(接口),让用户获得CCar类的一个实例的指针
MYDLL_API CCar* getCar(void);
dll里的一个实现文件
// MyDll.cpp : 定义 DLL 应用程序的导出函数。
//

#include "stdafx.h"
#include "MyDll.h"
#include <iostream>

// 这是导出函数的一个示例。
MYDLL_API CCar* getCar(void)
{
    std::cout << __FUNCTION__ << std::endl;
    CCar* car = new CCar;
    return car;
}

//CCar类的实现
CCar::CCar()
{

}

CCar::~CCar()
{

}

void CCar::Run()
{
    std::cout << "car run" << std::endl;
}

另外一个测试程序,通过隐式加载使用上面的dll,上面的dll已经顺利编译通过,并且生成lib和dll文件。

// DllTest.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "../MyDll/Mydll.h"
#include "iostream"


int _tmain(int argc, _TCHAR* argv[])
{
    CCar *car = getCar();//获取CCar的一个实例指针,但是编译阶段就会报错
    car->Run();
	return 0;
}
错误如下

错误 2error LNK1120: 1 个无法解析的外部命令 F:\ME\project\vs2013\DllTest\Debug\DllTest.exeDllTest
错误 1 error LNK2019: 无法解析的外部符号 "public: void __thiscall CCar::Run(void)" (?Run@CCar@@QAEXXZ),该符号在函数 _wmain 中被引用F:\ME\project\vs2013\DllTest\DllTest\DllTest.objDllTest

就是CCar的方法没有导出,导致链接出错,当然修改这个问题,只要在dll类的头文件里把CCar声明为导出类即可,如下

//导出的类 声明
class MYDLL_API CCar
{
public:
    CCar();
    ~CCar();
    void Run();
};
重现编译dll,再重新编译运行外部程序,即可成功调用。 运行结果如图所示:


当然这不是重点,有时候并不想把类导出,我只想通过我导出的接口让客户来使用,以前学习的时候有这样一种方法,不知道正不正规啊,但是有点类似COM组件的实现,通过虚函数来实现,再定义何以抽象类,让原来的CCar继承这个抽象类,那里面的类都不用声明为导出类,编译可以通过,并且正常使用。代码片段如下:

#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllimport)
#endif

//声明一个抽象类
class ICarBase
{
public:
    ICarBase(){}
    ~ICarBase(){}
    virtual void Run() = 0;
};

//导出的类 声明
class CCar : public ICarBase
{
public:
    CCar();
    ~CCar();
    void Run();
};

//导出的函数(接口)
MYDLL_API CCar* getCar(void);
上面的代码就增加了一个基类,把类中让用户想调用的函数声明为虚函数,那用户就可以调用这个类的函数(接口)了,同时类中声明的时候不用加上这个宏了,MYDLL_API,把这个宏从类声明中去掉。其余代码都不变。

这样就利用了虚函数动态绑定的原理,外部调用动态库中的类方法时,不用在编译阶段确定方法的地址,那就不用把类声明为导出类了,根据以前学的COM组件的一点小知识,COM组件用C++估计也是这样实现的把,没有深入研究过,自己的猜测而已。

回头看了看自己的第一篇博客,唉。。。。好难看啊,都表达不清楚。。。









  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值