先描述题目要表达的意思:我现在需要基于别人给的SDK,开发我自己的程序。例如基于别人给的miniBird.h、miniBird.lib和miniBird.dll,我自己写了一个类叫Bird,并且我开发的这个类也是需要给别人使用的,所以我也要提供Bird.h、Bird.lib和Bird.dll这三个文件给别人调用。
我肯定不想把我的实现文件.cpp提供给别人,我也不想让别人看到我定义的私有程序和其他不该看到的东西,就是说我只想给别人开放该看到的东西,他只需要调用这些接口就行,他也没有这个精力关心我是怎么实现的。这就涉及到类的封装了。
这篇文章就是讲如何开放接口,如何生成.h,.dll和.lib文件。
简单说,让你写的类派生于一个抽象类,抽象类封装了你的具体定义和函数,只需要在抽象类中开放你想开放的接口。
具体地,假设我现在已经写好了我的Bird类,也能正常运行了。并且已经新建好了应用程序类型为DLL的项目,名叫BirdClass,并且已经加入了加入了你已经写好的Bird.h和Bird.cpp文件了。
#pragma once
#include "miniBird.h"
class Bird
{
public:
Bird();
~Bird();
public:
void walk();
void fly();
void eat();
private:
int mouthnum;
int eyenum;
};
我的Bird.h文件里面定义了Bird类,从这个文件里面可以看到,包含了miniBird.h文件,定义了三个成员函数和两个私有的成员变量。
选择你想debug还是relese的配置。
选择relese,点击生成,在工程目录下的relese文件夹下就能看到Bird.dll文件了。
只有.dll文件,却没有.lib,该怎么办?
在Bird.h文件中加上下面的代码,然后生成,在打开relese文件夹,就可以看到.lib文件了。
#ifdef BIRDEXPORTS
#define Bird_API _declspec(dllexport)
#else
#define Bird_API _declspec(dllimport)
#endif
准确说叫创建.h文件。在看上文中Bird类的定义,我不想让别人看到我定义的两个私有变量,我也不想让别人知道我是基于“miniBird.h”这个文件来编写Bird类的,我只想给他walk,fly和eat三个接口。那如何只开放给别人该看到的接口呢?
这里用到了“指向子类的父类指针可以调用子类的函数”这么一个知识点。
第一、创建一个抽象类
先创建一个抽象类叫animal。
class animal
{
public:
animal() {};
virtual ~animal() {};
public:
virtual void walk() = 0;
virtual void fly() = 0;
virtual void eat() = 0;
};
第二、让Bird派生于抽象类
然后对Bird类做一个修改,让Bird派生于animal类。
#pragma once
#include "miniBird.h"
#include "animal.h"
#ifdef BIRDEXPORTS
#define Bird_API _declspec(dllexport)
#else
#define Bird_API _declspec(dllimport)
#endif
class Bird_API Bird:public animal
{
public:
Bird();
~Bird();
public:
void walk();
void fly();
void eat();
private:
int mouthnum;
int eyenum;
};
这里使用抽象类有几点好处:
animal.h文件作为提供给别人的文件,只定义了对外的接口内容,别人完全看不到你定义的Bird类里面有哪些内容,并且这个时候你的Bird类可以随意添加你自定义的函数和成员变量。
animal是一个抽象类,不能实例化,只需要写一个animal.h文件就可以了,不需要写.cpp。
animal抽象类可以作为一个统一的接口,例如下次再让你写一个叫elephant的类,你开放的接口还是只有fly,walk和eat的时候,这时elephant还是可以派生于animal,简化了开发步骤。
第二、创建工厂类
animal类和Bird类之间还需要建立联系,通过使用语句
animal* ani = new Bird();
父类指针ani就可以调用Bird类中的函数了。
在这里我们可以在创建一个工厂类AnimalFactory,用来建立animal和Bird的联系。AnimalFactory类的实现需要加入到.lib文件中,所以还需要加上
#ifdef FACEXPORTS
#define AnimalFac_API _declspec(dllexport)
#else
#define AnimalFac_API _declspec(dllimport)
#endif
这条语句。
AnimalFactory类的定义和实现如下。
//AnimalFactory.h
#include "animal.h"
#include "Bird.h"
#ifdef FACEXPORTS
#define AnimalFac_API _declspec(dllexport)
#else
#define AnimalFac_API _declspec(dllimport)
#endif
class AnimalFac_API AnimalFactory
{
public:
AnimalFactory();
~AnimalFactory();
animal* CreateObject();
void DeleteObject(animal* _ani);
};
//AnimalFactory.cpp
#include "stdafx.h"
#include "AnimalFactory.h"
AnimalFactory::AnimalFactory()
{
}
AnimalFactory::~AnimalFactory()
{
}
animal* AnimalFactory::CreateObject()
{
return new Bird;
}
void AnimalFactory::DeleteObject(animal* _ani)
{
if (_ani) delete _ani;
}
工厂类中的语句animal* AnimalFactory::CreateObject()获取到animal的指针之后便可以调用抽象类中的函数了,这句话将工厂类AnimalFactory和animal类联系起来了。那自然工厂类里面函数也需要给别人开放。
如何做到?再建立一个名叫“animalsdk.h”的文件,然后把animal类的定义和AnimalFactory类的定义直接拷贝到这个文件中,注意只要定义不需要实现,这样.h文件也就有了。代码如下:
//**这个文件里面还需要添加对外开放的一些结构体或者枚举类型**//
//**依照具体项目而定,目的只有一个**//
//**就是让别人更容易明白你的接口和编写程序**//
class animal
{
public:
animal() {};
virtual ~animal() {};
public:
virtual void walk() = 0;
virtual void fly() = 0;
virtual void eat() = 0;
};
class AnimalFactory
{
public:
AnimalFactory();
~AnimalFactory();
animal* CreateObject();
void DeleteObject(animal* _ani);
};
.h文件通俗来说只是起一个告知的作用,告诉自己,别人和编译器里面有哪些函数,有什么作用。所以最后一步建立的“animalsdk.h”文件可以随便命名,添加或者删减,因为这个文件没有参与到编译。
最后你需要提供的文件是:animalsdk.h,BirdClass.dll,BirdClass.lib。
WOODS 2019/5/11