如何封装一个类 C++接口版

先描述题目要表达的意思:我现在需要基于别人给的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文件,定义了三个成员函数和两个私有的成员变量。

01

生成.dll

选择你想debug还是relese的配置。

在这里插入图片描述

选择relese,点击生成,在工程目录下的relese文件夹下就能看到Bird.dll文件了。

02

生成.lib

只有.dll文件,却没有.lib,该怎么办?

在Bird.h文件中加上下面的代码,然后生成,在打开relese文件夹,就可以看到.lib文件了。

#ifdef BIRDEXPORTS
#define Bird_API _declspec(dllexport)
#else
#define Bird_API _declspec(dllimport)
#endif

03

生成.h

准确说叫创建.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;
};

这里使用抽象类有几点好处:

  1. animal.h文件作为提供给别人的文件,只定义了对外的接口内容,别人完全看不到你定义的Bird类里面有哪些内容,并且这个时候你的Bird类可以随意添加你自定义的函数和成员变量。

  2. animal是一个抽象类,不能实例化,只需要写一个animal.h文件就可以了,不需要写.cpp。

  3. 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

好的,以下是一个简单的示例代码: ```c++ #include <jni.h> #include <iostream> class Calculator { public: int add(int a, int b) { return a + b; } }; extern "C" { JNIEXPORT jlong JNICALL Java_com_example_calculator_CalculatorWrapper_createCalculator(JNIEnv* env, jobject thiz) { return reinterpret_cast<jlong>(new Calculator()); } JNIEXPORT void JNICALL Java_com_example_calculator_CalculatorWrapper_destroyCalculator(JNIEnv* env, jobject thiz, jlong ptr) { auto calculator = reinterpret_cast<Calculator*>(ptr); delete calculator; } JNIEXPORT jint JNICALL Java_com_example_calculator_CalculatorWrapper_add(JNIEnv* env, jobject thiz, jlong ptr, jint a, jint b) { auto calculator = reinterpret_cast<Calculator*>(ptr); return calculator->add(a, b); } } ``` 在这个示例中,我们定义了一个名为 `Calculator` 的 C++ ,其中包含一个 `add` 方法,用于计算两个整数的和。然后,我们使用 `extern "C"` 关键字将这些方法包装为 JNI 接口。具体来说: - `Java_com_example_calculator_CalculatorWrapper_createCalculator` 方法用于创建 `Calculator` 对象,并返回其地址。 - `Java_com_example_calculator_CalculatorWrapper_destroyCalculator` 方法用于销毁 `Calculator` 对象。 - `Java_com_example_calculator_CalculatorWrapper_add` 方法用于调用 `Calculator` 对象的 `add` 方法,并返回结果。 在这个示例中,我们假设使用者已经正确地将 `CalculatorWrapper` 包装为了 JNI 接口,因此我们可以直接使用该的方法。如果您需要了解如何将 C++ 包装为 Java 并使用 JNI 接口,请参阅相关文档或示例。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值