Skip to main content

関数ポインタについて(by チョコミント)

関数ポインタについて

初めまして、チョコミントと申します。 これからゲーム制作の際に使えそうな便利なものなど、勉強感覚で記事にアップしていくので良ければ赤ちゃんを見る気持ちで見ていただけると嬉しいです...!!!

さて、初めての記事は何を書こうか悩んだのですが、汎用的に使えそうな関数ポインタについて触れていこうかなと思います。

関数ポインタとは

簡単に説明すると「関数」を参照している「ポインタ」のことです。 まあ変数のポインタと同じようなものですね!

void Test() { std::cout << "Hello"; }
int main()
{
	void (*func)() = Test;
	func();
}

上のコードではTest関数のポインタつまりアドレスをfuncに格納し funcを呼ぶことでHelloが表示されます。

ラムダ式を使って関数ポインタに登録してみる

みなさんは「ラムダ式」という言葉を聞いたことがありますか? 私も完璧には理解していないのですが、「疑似的に関数を作れる」みたいなことです。

int main()
{
	void (*func)() = []() { std::cout << "Hello"; };
	func();
}

上のコードではラムダ式 [キャプチャ](引数 ) {...} で関数を作成しfuncに登録しています。 funcを呼ぶことでHelloが表示されます。

ラムダ式の[]の部分にはキャプチャリストを記述できます。 つまりラムダ式のスコープ外にあるものを参照できるわけです。便利ですね...

int main()
{
	std::string str = "ぴえん";

	std::function<void()> func = [str]() { std::cout << str; };
	func();
}

上のコードではstr変数をキャプチャすることでstrを参照し ぴえんを表示しています。 キャプチャしたものはconstなので値は変更できません。

ここで「std::function<void()>」という新しいものがでてきました。 std::functionというものは関数ポインタ、関数オブジェクト、メンバ関数ポインタ、メンバ変数ポインタを保持できるクラスです。 えええ!!!!  ってことはstd::functionを使うことで、メンバ関数ポインタを保持できるってことは多種多様な機能が実現できるかも!!!

class Collider
{
	std::function<void()> hitfunc_; //コライダー同士がヒットした時に呼ばれる
	std::function<void()> exitfunc_; //コライダー同士が離れた時に呼ばれる

	bool isbeforeHit_;

public:

	Collider(std::function<void()> hit, std::function<void()> exit) 
		:isbeforeHit_(false),hitfunc_(hit),exitfunc_(exit){}

	//当たり判定
	void CollisionDetection()
	{
		bool isHit = true;

		//当たり判定を行う
		//...
		//...

		if (isHit && !isbeforeHit_)
			hitfunc_();
		else if (!isHit && isbeforeHit_)
			exitfunc_();

		isbeforeHit_ = isHit;
	};
};


class GameObject
{
public:

	std::unique_ptr<Collider> collider_;

	GameObject() 
	{
		collider_ = std::make_unique<Collider>([&]() { return HitFunc(); }, [&]() { return ExitFunc(); });
	}

	void HitFunc() { std::cout << "Hit"; };
	void ExitFunc() { std::cout << "Exit"; };
};

int main()
{
	std::unique_ptr<GameObject> obj = std::make_unique<GameObject>();
	obj->collider_->CollisionDetection();
}

上のコードではコライダークラスにあらかじめヒットした時、離れた時用の関数ポインタなどを保持するstd::function<void()>型の変数を用意しておきます。 ゲームオブジェクトクラスで好きな関数をラムダ式の中で呼び出しそれを登録します。 このコードを実行してみるとhitfunc_();が呼ばれHitが表示されます。

コライダーごとに当たった後、離れた後の挙動を変更したい時などとてもおすすめなんです!! みなさんもぜひ活用してみたください!

最後に

初めて記事を書いたので、至らない点などが多かったと思いますが、最後まで見ていただきありがとうございます!! 質問やわからなかったことなどがあればぜひ気軽にコメントしてください!