TransWikia.com

C++の継承したクラスをコールバッククラスとして引数として渡しその中の関数をわかりやすく記述したい

スタック・オーバーフロー Asked on September 1, 2021

ESP32というCPUの開発環境上のBLEを扱おうと思っているのですが
その中でコールバッククラスの扱いがわからなくて困っています
VSCode + Platoform IOと言う環境です
もとはAruduino形式のプログラムです(setupとloopがあらかじめ決められている)

元のプログラムではクラスでは無く、直接CPP上で記載されていて、プログラムは以下のようになっています

//データを受信するとMyCallbaksがコールされ、onWrite関数内の命令を実行する
//https://dev.classmethod.jp/articles/esp32_ble_debug_tool/
//こちらのサンプルを使用
class MyCallbacks: public BLECharacteristicCallbacks {//●コールバッククラスの本体
    void onWrite(BLECharacteristic *pCharacteristic) {//●onWriteが元のクラス内でvirtualで宣言されていて、この関数を自作して受信したデータの値を取り出す
      uint8_t* iData = pCharacteristic->getData();
      char str[100];

      for(int i=0;i<100;i++){
        sprintf(str,"data=%2x",*iData);
        iData++;
        Serial.print(str);
        Serial.print(" ");
      }
    }
};

pCharacteristic->setCallbacks(new MyCallbacks());//●ここでコールバッククラスを登録

それをBLE関連のクラスにまとめてみようと思ったのですが

  1. BLECharacteristicCallbacks の中身のonWriteをヘッダファイルでは無く、
    CPPファイル側に記述したい
  2. BleOreyouクラスに値を渡す

と言うところで躓いています
以下のように記述してみたのですがそこから先がどのように記述すればいいのか・・・

Class BleOreyou{
public:
    void OnWrite2(BLECharacteristic *pCharacteristic);

//..省略
    class MyCallbacks: public BLECharacteristicCallbacks {
        void onWrite(BLECharacteristic *pCharacteristic) {//●この関数をcpp側に記述したい
            OnWrite2(pCharacteristic);                    //●BleOreyouクラスに渡してデータ操作、他のクラスへのイベントの起点にしたい
#if 0

      uint8_t* iData = pCharacteristic->getData();
      char str[100];

      for(int i=0;i<100;i++){
        sprintf(str,"data=%2x",*iData);
        iData++;
        Serial.print(str);
        Serial.print(" ");
      }
#endif
    };
}

One Answer

A1. そもそも論として virtual な関数をヘッダファイルにて関数定義してもインライン展開されることは期待できない(というより不可能)なので、ごく普通に「ヘッダファイルでクラス定義とメンバ関数宣言」「 CPP ファイルでメンバ関数定義」すればよいだけのことです。

-- hoge.h --

// クラス定義
class derived1_type : public base_type {
    // メンバ関数宣言
    virtual void OnEvent(event_arg_type& ev);
};

-- hoge.cpp ---

#include "hoge.h"
void derived1_type::OnEvent(event_arg_type& ev) {
    // 何か処理
}

A2. なにをどう渡すのか微妙に不明ですが、この手のコールバックの仕組みというのは

ライブラリというかフレームワークというか側に

bool framework_type::register_callback(base_type& r) { ... }

のような関数があるのが普通です。となると

コールバックしてもらう側(フレームワークのユーザー)の責務は

  • base_type 派生クラスのインスタンスを用意する(コールバックをしてもらう必要がある間ずっと有効でなければならない:ウィンドウのメンバとかにする必要がある)
  • register_callback() にその参照を渡してフレームワーク内に保持してもらう
  • コールバックが不要になったら unregister_callback() などの手段でやめてもらう

コールバックする側(フレームワーク自体)の処理は

  • 登録削除は先の説明と同等
  • コールバック一覧に登録されている this の仮想関数を呼び出す

つまりフレームワーク側の実装例は

for (base_type& c : callbacklist) {
    c.OnEvent(ev);
}

(当該 BLECharactaristicCallbacks の仕様は未調査)

なのであなたのすべきことは

  • MyCallbacks インスタンスを生成してずっと保持する
  • MyCallbacks インスタンスをコールバックに登録する(以下略)

BleOreyou に当該 MyCallbacks インスタンスを保持しておけば何も悩むことはないような気がします。っていうか MyCallbacksBleOreyou から分離して別クラスにするから意味なく悩ましくなっているだけの疑いが残ります。

Correct answer by 774RR on September 1, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP