1

おそらく実際には「従来型」ではないことをしているときに、C++ コンパイル エラーが発生しました。簡単にするために、使用しようとしているメカニズムを読みやすい方法で書き直し、同じ問題が発生することを確認しました。

まず、コードは次のとおりです。

test.h // - - C++ - -

template <typename MODULE> class item;

template <typename MODULE>
class init {
public:
  typedef int (MODULE::*funcPtr)(int);
private:
  funcPtr m_fp;
public:
  init& has_funcPtr(funcPtr fp) { m_fp = fp;}
  init() {}
  virtual ~init() {}
private:
  friend class item<MODULE>;
};

template <typename MODULE>
class item {
public:
  typedef int (MODULE::*funcPtr)(int);
private:
  funcPtr m_fp;
public:
  item(init<MODULE> params) : m_fp(params.m_fp) {}
  virtual ~item() {}
};

class user {
public:
  typedef init<user>::funcPtr funcPtr;
private:
  // Method CB
  int func1(int i);
  // Item member
  item<user> m_item;
public:
  user();
  virtual ~user();
};

test.cpp // - - C++ - -

#include "test.h"

user::user() : m_item(init<user>().has_funcPtr(this->func1) ) {}

int user::func1(int i) {return 1;}

ここにエラーがあります:

/test.cpp:5:59: error: invalid use of non-static member function
 user::user() : m_item(init<user>().has_funcPtr(this->func1) ) {
                                                       ^

したがって、これが私が望むものを達成するための最良の方法であるかどうかはわかりません (おそらくそうではありませんが、他の提案があれば大歓迎です)。しかし、私の目標は、それを機能させるか、なぜ機能しないのかを正確に理解することです。そこから何かを学べるように!

基本的な考え方は次のとおりです。

  • クラス「item」は、「init().has_funcPtr(&function_name)」のようにコンストラクターに連結されたクラス「init」のメソッド「has_funcPtr」を使用して、名前付きパラメーターイディオムで初期化できます。
  • クラス "user" は、そのプライベート メソッド "func1" へのポインタを、型 "item" のプライベート メンバのプライベート メンバとして格納できます。

このようにして、オブジェクト「項目」の特定のメソッドが呼び出されたとき (簡単にするために、この長い部分はエラーとは関係がないため、ここには含めませんが、このコード スニペットの目的を説明するだけです)そのメソッドは、関数へのポインターを介して、何かを実行し、その親オブジェクト「ユーザー」のプライベートメソッドを呼び出すことができます(これが十分に明確であることを願っています...)。

現在、オブジェクトの初期化の順序に問題があると思いますが、どこでどのように修正すればよいかわかりません。特に、「func1」メソッドはクラス「user」のどのメンバーでも動作しないため、その参照を初期化リストで直接使用して「init」オブジェクトを初期化し、それを「item」にフィードできると考えました" 物体。

よろしくお願いします

4

2 に答える 2

0

私の問題に対する完全な回答をここに投稿します。Boからの提案の後、インスタンス固有のメソッドへのポインターを介してインスタンス固有のメソッドを指す方法を理解した後、私はそれを開発しました。

要するに、次の 2 つの点に注意することが非常に重要です。

  1. 非静的クラス メンバー関数へのポインターは、「絶対アドレス」ではなく単なるオフセットと見なすことができます ( http://www.codeguru.com/cpp/cpp/article.php/c17401/C-Tutorial- PointertoMember-Function.htm )。これは、最初にインスタンス ポインターがないと、その関数にアクセスできないことを意味します (これは単なるオフセットです)。インスタンス ポインタを取得したら、この「オフセット ポインタ」を使用して、次を使用してそのメソッドを呼び出すことができます。

    (object_ptr->*method_ptr)(parameters_here)

    この構文は実際にエラーが発生しやすく、読み取りが複雑であるため、 #define マクロを使用することをお勧めします ( https://isocpp.org/wiki/faq/pointers-to-members ):

    #define CALL_MEMBER_FN(ptrToObject,ptrToMember) ((ptrToObject)->*(ptrToMember))

    そしてそれを次のように使用します:

    CALL_MEMBER_FN(object_ptr, method_ptr)(parameters_here)

  2. 最初のポイントに続いて、ネストされたクラスが上位クラスのメソッドをそれへのポインターで呼び出すことができるようにする場合は、その関数にアクセスするために上位クラスのインスタンス ポインターも渡す必要があります。私の場合、そのメソッドを呼び出すかどうかをケースバイケースで決定できるようにしたかったので、名前付きパラメーターのイディオムを使用しました (たとえば、func2 は登録されていないことに注意してください)。

最後に、動作する(テスト済み)改訂コードを次に示します。

- - C++ - - test.h

#include <iostream>

template <typename MODULE> class item;

template <typename MODULE>
class init {
public:
  typedef int  (MODULE::*funcPtr)(int);
  typedef bool (MODULE::*func2Ptr)(bool);
private:
  funcPtr  m_fp;
  func2Ptr m_fp2;
  MODULE* m_dad;
public:
  init& has_funcPtr(funcPtr fp) { m_fp = fp; return *this;}
  init& has_func2Ptr(func2Ptr fp2) { m_fp2 = fp2; return *this;}
  init(MODULE* dad) : m_dad(dad) { std::cout << "init constructor called\n"; }
  ~init() {}
private:
  friend class item<MODULE>;
};

template <typename MODULE>
class item {
public:
  typedef int  (MODULE::*funcPtr)(int);
  typedef bool (MODULE::*func2Ptr)(bool);
private:
  funcPtr  m_fp;
  func2Ptr m_fp2;
  MODULE*  m_dad;
public:
  item(init<MODULE> params) :
    m_fp(params.m_fp),
    m_fp2(params.m_fp2),
    m_dad(params.m_dad)
  {
    std::cout << "item constructor called\n";
  }
  ~item() {}
  // Method invoked externally
  int callback() {
    std::cout << "item class method callback invoked\n";
    // In the real case here do general stuff
    if(m_fp) {
      int i = (m_dad->*m_fp)(1); // call member function through its pointer
      return i;
    } else {
      std::cout << "callback not registered\n";
      return 0;
    }
  }
  // Method invoked externally
  bool callback2() {
    std::cout << "items class method callback2 invoked\n";
    // In the real case here do general stuff
    if(m_fp2) {
      bool b = (m_dad->*m_fp2)(true); // call member function through its pointer
      return b;
    } else {
      std::cout << "callback2 not registered\n";
      return false;
    }
  }
};

class user {
public:
  typedef init<user>::funcPtr funcPtr;
private:
  // Methods that optionally add more functionalities to the 2 callbacks
  int  func1(int i);
  bool func2(bool b);
public:
  // Item member
  item<user> m_item;
public:
  user();
  ~user();
};

- - C++ - - test.cpp

#include "test.h"

user::user() : m_item(init<user>(this).has_funcPtr(&user::func1) ) {
  std::cout << "user constructor called\n";
}

int user::func1(int i) {return i;}
bool user::func2(bool b) {return b;} // func2 won't be registered


int main() {
  user* u = new user();
  // Test callbacks
  int i = u->m_item.callback();
  bool b = u->m_item.callback2();
  std::cout << "main is printing i=" << i << " and b=" << b << "\n";
  std::cout << "expected results are i=1 and b=0\n" << "END\n";
  return 0;
}

出力:

init constructor called
item constructor called
user constructor called
item class method callback invoked
items class method callback2 invoked
callback2 not registered
main is printing i=1 and b=0
expected results are i=1 and b=0
END
于 2015-10-21T15:14:56.493 に答える