読者です 読者をやめる 読者になる 読者になる

ちぎっては投げるブログ

Programming, Android, RaspberryPi, Digital Devices, Kinkuma Hamster...

C++のクラスメンバ関数の関数ポインタについて

Programming C/C++

C++のクラスのメンバ関数を、関数ポインタ指定して外から呼ぶのを何も考えずにやろうとすると、呼び出すことが出来ずに嵌まる。 何故かというと、クラスの関数ポインタは、インスタンスごとに作られてるわけではないから。どのインスタンスの関数であるのか知るために、内部的にインスタンスのポインタ(thisポインタ)をメンバ関数の引数に与えている。

なので、どうしてもクラスメンバ関数のポインタ呼び出しをしたい場合には、専用の呼び出し方があり、その呼び方で呼ぶ必要がある。そうすると、本来不要である依存が発生する場合がある。(たぶん)

ロベールのC++教室 - 第57章 メンバ関数ポインタ天国 -

依存をなくすために、違う方法を考えてみる。 インスタンスごとに別の関数ポインタを持つようにstaticなメンバ関数にする。staticであれば、普通に関数ポインタで呼び出せる。しかし、関数内で、自身のstaticなメンバにしかアクセス出来なくなり困ることになる。そこで、static関数の引数に、自身のインスタンスのvoidポインタを渡すようにする。関数内でメンバ変数を触るときは、引数で渡したインスタンスへのポインタを自分の型にキャストして触ればよい。これで依存関係も気にせずに、クラスのメンバ関数を関数ポインタで呼び出せる。 ただし、正しくキャスト出来るデータが渡されていることが前提となるし、voidポインタを使うと型情報を頼りにコードを読むのが難しくなるので、これで本当に正しいのかはまた考える。

追記 こんなイメージ。出力は1

#include <iostream>

class MyClass
{
public:
    MyClass();
    ~MyClass();
    static void func(void* self);
private:
    const int NUM = 1;

};

MyClass::MyClass()
{
}

MyClass::~MyClass()
{
}

void MyClass::func(void* self){
    std::cout << static_cast<MyClass*>(self)->NUM << std::endl;
}


class MyClass2
{
public:
    MyClass2();
    ~MyClass2();
    void func2(void* self, void(*fpFunc)(void*));
private:
};

MyClass2::MyClass2()
{
}

MyClass2::~MyClass2()
{
}

void MyClass2::func2(void* self, void(*fpFunc)(void*)){
    fpFunc(self);
}


int main(){
    MyClass mcls = MyClass();
    MyClass2 mcls2 = MyClass2();
    mcls2.func2(&mcls, MyClass::func);
}