0

以下のクラスを使用するドライバを書きたいのですが、このクラスの宣言と使い方がわかりません。この授業を理解したい、使ったので、この授業を深く理解するために何を学びたいか。よろしくお願いします!:

typedef void (*pvoidf_t)(void);

/* A class for storing and calling a pointer to a static or member void function */

class FunctionPointer {

public:

    FunctionPointer(void (*function)(void) = 0);

    /** Create a FunctionPointer, attaching a member function
     *
     *  @param object The object pointer to invoke the member function on (i.e. the this pointer)
     *  @param function The address of the void member function to attach
     */
    template<typename T>
    FunctionPointer(T *object, void (T::*member)(void)) {
        attach(object, member);
    }

    /** Attach a static function
     *
     *  @param function The void static function to attach (default is none)
     */
    void attach(void (*function)(void) = 0);

    /** Attach a member function
     *
     *  @param object The object pointer to invoke the member function on (i.e. the this pointer)
     *  @param function The address of the void member function to attach
     */
    template<typename T>
    void attach(T *object, void (T::*member)(void)) {
        _object = static_cast<void*>(object);
        memcpy(_member, (char*)&member, sizeof(member));
        _membercaller = &FunctionPointer::membercaller<T>;
        _function = 0;
    }

    /** Call the attached static or member function
     */
    void call();

    pvoidf_t get_function() const {
        return (pvoidf_t)_function;
    }

private:

    template<typename T>
    static void membercaller(void *object, char *member) {
        T* o = static_cast<T*>(object);
        void (T::*m)(void);
        memcpy((char*)&m, member, sizeof(m));
        (o->*m)();
    }

    void (*_function)(void);                // static function pointer - 0 if none attached
    void *_object;                            // object this pointer - 0 if none attached
    char _member[16];                        /* raw member function pointer storage - converted back by registered _membercaller */
    void (*_membercaller)(void*, char*);    /* registered membercaller function to convert back and call _member on _object */

};
4

1 に答える 1

0

まず、コメントに対処します。

template<typename T>
FunctionPointer(T *object, void (T::*member)(void)) {
    attach(object, member);
}

クラスのこの部分は、メンバー関数テンプレートと同様に、コンストラクター テンプレートを宣言します。パラメータは次のとおりです。

  • という名前のタイプのオブジェクトへのポインタTobject
  • パラメータも戻り値も持たないという名前のメンバー関数へTのポインタmember

後者の構文は次のように読むことができます。

void   (T  ::  *  member)  (void)
^       ^      ^  ^        ^ argument list
|       |      |  | name of the parameter
|       |      | it's a pointer
|       | class type
| return type

さて、残りの機能:

FunctionPointer(void (*function)(void) = 0);

これは、 という名前の、パラメーターも戻り値もない関数へのパラメーター ポインターを持つ (非テンプレート) コンストラクターfunctionです。パラメータにはデフォルトの引数があります0

メンバー関数のオーバーロードのシグネチャはattach、コンストラクターと同様に理解できます。

get_function最後に typedef: を使用します。これは、パラメーターも戻り値もない関数へtypedef void (*pvoidf_t)(void);の型ポインターのエイリアスを定義します。これは、そのクラスの非テンプレート関数 (およびコンストラクター) に対しても実行できます。

FunctionPointer(pvoidf_t function = 0);

これは、上記の非テンプレート コンストラクターの宣言と同等の代替です。


クラス全体は、関数ポインターまたはメンバー関数ポインターのいずれかを格納するためのものです。静的メンバー関数へのポインターは自由関数へのポインターと変わりませんが、非静的メンバー関数へのポインターは次のとおりです。少なくとも、動作するクラスのインスタンスが必要です。

struct my_class
{
    int m;
    void set_m() { m = 42; }
};

typedef void (my_class::*mem_fun_ptr)();
mem_fun_ptr p_set_m = &my_class::set_m;

my_class instance;
(instance.*p_set_m)(); // we need an instance to call the member function

したがって、メンバ関数ポインタを格納する場合、クラスFunctionPointerはインスタンスへのポインタも格納する必要があります。

2 つ目の問題は、メンバー関数ポインターのがメンバー関数のクラスに依存するために発生します。の型はvoid (class_A::*)()とは異なりvoid (class_B::*)()ます。

関数membercallerとプライベート変数から、これらの問題が でどのように解決されるかを推測できますFunctionPointer

  • 通常の (自由な) 関数ポインターの場合、データ メンバー_functionが使用されます。
  • 任意のメンバー関数ポインターの場合:
    1. データメンバー_objectは、渡されたインスタンスを指すように設定されています
    2. メンバー関数ポインターがバッファー (できれば十分な大きさ)、データ メンバーにコピーされます。_member
    3. データ メンバーは、静的関数テンプレート_membercallerのインスタンスを指すように設定されています。membercallerこれは重要なステップです。 ctor/ 内attachでは、メンバー関数ポインターのクラス型はまだわかっていますが、戻るとこれを失います。したがって、型は、参照するmembercallerテンプレートのインスタンスで「エンコード」されます。この関数は、そのテンプレート パラメーターにより、クラスの型を "認識" しています。異なるクラス タイプごとに、新しいmembercallerインスタンスが作成されます (例:などmembercaller<class_A>) membercaller<class_B>。これらは異なる関数であり、場合によってはアドレスが異なり、動作が異なる場合があります。
    4. データメンバー_functionはに設定されています0

さらに推測: どの呼び出しでも、メンバー関数callが使用されます。そう_functionでない場合は0、直接呼び出します_function()_functionがの場合0、 を呼び出します。これは、メンバー関数呼び出しの「正しい」クラス タイプを持つ の_membercaller(_object, _member)インスタンスへの呼び出しに解決されます。membercaller


このクラスの使用方法の 2 つの例:

void my_function() {
    // do something
}

FunctionPointer myptr(&my_function);
// store myptr, do something else
myptr.call();  // calls (indirectly) `my_function`

メンバー関数ポインターの場合:

struct my_class {
    int m;
    void my_function() { /*...*/ }
};

my_instance inst = {42};

FunctionPointer myptr(&inst, &my_class::my_function);
// store myptr, do something else

// make sure `inst` lives until after the call!
myptr.call();  // calls (indirectly) `inst.my_function()`
于 2013-10-03T13:35:49.250 に答える