HarmonyOS 如何将c++的虚基类封装并提供给ArkTS

现因项目需求,需要将c++中的虚基类提供给上层ArkTS,但教程中所有函数公开,只能定义为static成员函数 而不能定义为virtual或普通成员函数,请告知如何将 irtual函数导致到ArkTS中使用。

HarmonyOS
1天前
浏览
收藏 0
回答 1
待解决
回答 1
按赞同
/
按时间
zxjiu

ArkTS调用C++类中的成员函数,其中成员函数分为普通函数和静态成员函数,区别是普通成员函数需要创建一个JS实例与C++实例绑定,而静态函数不需要。

在C++中定义一个类:

class AddClass {
  public:
    AddClass(std::string name)
    {
      this->instName = name;
    };
   AddClass(){};
   ~AddClass(){};
   std::string instName;
   double Add(double a, double b)
   {
     return a+b;
   };
   static double StaticAdd(double a, double b)
   {
     return a + b;
   };
};

为这个类绑定构造函数:

static napi_value JsConstructor(napi_env env, napi_callback_info info) {
  // 创建napi对象
  napi_value jDemo = nullptr;

  size_t argc = 1;
  napi_value args[1] = {0};

  // 获取构造函数入参
  napi_get_cb_info(env, info, &argc, args, &jDemo, nullptr);

  // args[0] js传入的参数
  char name[50];
  size_t result = 0;
  napi_get_value_string_utf8(env, args[0], name, sizeof(name) + 1, &result);

  // 创建C++对象
  AddClass *cDemo = new AddClass(name);
  //OH_LOG_INFO(LOG_APP, "%{public}s", (cDemo->instName).c_str());

  // 设置js对象name属性
  napi_set_named_property(env, jDemo, "name", args[0]);

  // 绑定JS对象与C++对象
  napi_wrap(
    env, jDemo, cDemo,
    // 定义js对象回收时回调函数,用来销毁C++对象,防止内存泄漏
    [](napi_env env, void *finalize_data, void *finalize_hint) {
    AddClass *cDemo = (AddClass *)finalize_data;
    delete cDemo;
    cDemo = nullptr;
  },
  nullptr, nullptr);
  return jDemo;
}

这个C++类将与JS侧的类绑定,在JS侧的类创建时,这个C++的构建函数也将调用。

为类中普通函数Add()提供js侧接口:

static napi_value JsAdd(napi_env env, napi_callback_info info) {
  size_t argc = 2;
  napi_value args[2] = {nullptr};
  napi_value jDemo = nullptr;
  napi_get_cb_info(env, info, &argc, args, &jDemo, nullptr);
  AddClass *cDemo = nullptr;
  // 将js对象转为c对象
  napi_unwrap(env, jDemo, (void **)&cDemo);
  // 获取js传递的参数
  int value0;
  napi_get_value_int32(env, args[0], &value0);
  int value1;
  napi_get_value_int32(env, args[1], &value1);
  int cResult = cDemo->Add(value0, value1);
  napi_value jResult;
  napi_create_int32(env, cResult, &jResult);
  return jResult;
}

为类中静态函数StaticAdd()提供js侧接口:

static napi_value JsStaticAdd(napi_env env, napi_callback_info info) {
  size_t argc = 2;
  napi_value args[2] = {nullptr};
  napi_value jDemo = nullptr;
  napi_get_cb_info(env, info, &argc, args, &jDemo, nullptr);
  // 获取js传递的参数
  int value0;
  napi_get_value_int32(env, args[0], &value0);
  int value1;
  napi_get_value_int32(env, args[1], &value1);
  int cResult = AddClass::StaticAdd(value0, value1);
  napi_value jResult;
  napi_create_int32(env, cResult, &jResult);
  return jResult;
}

通过对比可以发现普通函数,需要绑定一个C++类的实例,而静态函数不需要。

在init函数中暴露C++的类和类中的函数,并引入JS侧对应要绑定的类:

static napi_value Init(napi_env env, napi_value exports) {
  // 定义模块需要对外暴露的方法

  // 通过napi_define_class建立JS类与C++侧的映射关系,然后将对应的对象挂载到export上
  napi_property_descriptor classProp[] = {{"Add", nullptr, JsAdd, nullptr, nullptr, nullptr, napi_default, nullptr},
  {"StaticAdd", nullptr, JsStaticAdd, nullptr, nullptr, nullptr, napi_static, nullptr}};

napi_value jDemo = nullptr;
const char *jDemoName = "AddClass";
// 建立JS构造函数与C++方法的关联,指定2个prop
napi_define_class(env, jDemoName, sizeof(jDemoName), JsConstructor, nullptr,
  sizeof(classProp) / sizeof(classProp[0]), classProp, &jDemo);
napi_set_named_property(env, exports, jDemoName, jDemo);
return exports;
}

在index.d.ts中导出AddClass:

export const add: (a: number, b: number) => number;
declare namespace testNapi {
  class AddClass {
    constructor(name:string)
    name: string
    Add(a: number, b: number): number
    static StaticAdd(a: number, b: number): number
  }
}
export default testNapi;

在ArkTS侧调用native侧类函数:

import hilog from '@ohos.hilog';
import testNapi from 'libentry.so';

@Entry
@Component
struct Index {
  @State message: string = 'Hello World';

  build() {
    Row() {
      Column() {
        Text(this.message)
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
          .onClick(() => {
            //调用构造函数,获取对象
            let AddClass = new testNapi.AddClass("class name");
            hilog.info(0x0000, 'ckTest', 'Test NAPI 3 + 7 = %{public}d', AddClass.Add(3, 7));
          })
        Button('static add')
          .onClick(() => {
            hilog.info(0x0000, 'ckTest', 'Test NAPI static 8 + 5 = %{public}d', testNapi.AddClass.StaticAdd(5,8));
          })
      }
      .width('100%')
    }
    .height('100%')
  }
}

通过对比可以发现,类中的普通函数需要创建一个js类实例并通过绑定来调用C++类的构造函数来在native侧创建一个对应C++类,在调用类函数时通过类实例来调用。而static函数就不需要创建JS类实例和C++实例,可以直接调用。

分享
微博
QQ
微信
回复
1天前
相关问题
有无ArkTS编码规范可以提供给开发者
2214浏览 • 1回复 待解决
HarmonyOS 如何封装页面
472浏览 • 1回复 待解决
aki是否支持C++函数和callback?
874浏览 • 1回复 待解决
如何将js传map转成c++对象
760浏览 • 1回复 待解决
ArkTS调用C++成员函数
1356浏览 • 1回复 待解决
HarmonyOS能够提供页面的吗?
448浏览 • 1回复 待解决
如何C/C++ 创建ArkTS对象
2281浏览 • 1回复 待解决
HarmonyOS ArkTSC/C++交互
797浏览 • 1回复 待解决
如何实现ArkTSC/C++数组转换
801浏览 • 1回复 待解决