メンバ関数ポインタにメンバ関数のアドレスを代入したい

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
nam

メンバ関数ポインタにメンバ関数のアドレスを代入したい

#1

投稿記事 by nam » 10年前

今ゲームを作っています
敵が出現するごとにEnemyクラスをnewするのは遅くなると聞きました。
なので初めにすべてnewしておいてパラメタで処理を分岐させる設計にしたいのです。

そこでEnemy::draw()とEnemy::upData()は関数ポインタという形で持っておき、create()するときに適切な描画関数と更新関数に結び付けよう、思いました。

しかし、結び付けるために代入しようとするとC2440コンパイルエラーになってしまいます。
なぜエラーになるのか、どのように解決すればよいか、お教えくださるとありがたいです。

コードは以下です。
ZACは敵キャラの名前です。

敵クラス

コード:

 
class Enemy{
	friend class EnemyCompany;
public:
	Enemy() :
		m_x(0.f), m_y(0.f), m_r(0.f),
		m_hp(0.f),
		m_isLive(false),
		m_counter(0),
		draw( 0 ), upData( 0 )
	{};
	static void setImage(int img){ m_image = img; };
	bool getIsLive(){ return m_isLive; }
	bool getIsHit(float x, float y, float r){
		return ((m_x - x)*(m_x - x) + (m_y - y)*(m_y - y) < (m_r + r)*(m_r + r)); 
	}

	void (*upData)(BulletCompany* bullet);
	void (*draw)();

	void create(float x, float y,EnemyType type);
private:
	static int m_image;
	float m_x, m_y, m_r, m_hp;
	bool m_isLive;

	int m_counter;

	Enemy* Next;
	Enemy* Prev;


	//type別のdrawとupData

	void drawZAC();

	void upDataZAC(BulletCompany* bullet);
};
Enemy::create()

コード:

 
void Enemy::create(float x,float y,EnemyType type){

	m_x = x;
	m_y = y;
	m_isLive = true;
	m_counter = 0;

	switch (type){
	case ENEMY_ZAC:
		draw = Enemy::drawZAC;            //ここと
		upData = Enemy::upDataZAC;;    //ここでエラーが出る
		m_r = 16.f;
		m_hp = 60.f;
		break;
	}

}

アバター
usao
記事: 1889
登録日時: 11年前

Re: メンバ関数ポインタにメンバ関数のアドレスを代入したい

#2

投稿記事 by usao » 10年前

drawとupDataが ただの(普通の関数用の)関数ポインタとして宣言されています.
メンバ関数ポインタは
void (Enemy::*draw)();
のように宣言します.

あと,主題ではないけど,
メンバ変数であるdrawとupDataはprivateにすべきではないかな.

nam

Re: メンバ関数ポインタにメンバ関数のアドレスを代入したい

#3

投稿記事 by nam » 10年前

お返事ありがとうございます!

ご指摘通りvoid (Enemy::*draw)()としました。
すると今度は別のエラーがでました。
なのでdrawをdrawAに、upDataをupDataAという名前に変えてprivateにし、
新しくメンバ変数void draw(){ (this->*drawA)(); }のように付け加えるとちゃんと動きました!

ありがとうございました

アバター
usao
記事: 1889
登録日時: 11年前

Re: メンバ関数ポインタにメンバ関数のアドレスを代入したい

#4

投稿記事 by usao » 10年前

オフトピック
>なのでdrawをdrawAに、upDataをupDataAという名前に変えてprivateにし、

その A に何らかの意味(何かの単語の略とか?)があるのなら良いのですが,
そうでないなら もうちょっと変数名をちゃんとした方がいいのでは…とか.
(upData というのも綴り間違いな気もする)

nam

Re: メンバ関数ポインタにメンバ関数のアドレスを代入したい

#5

投稿記事 by nam » 10年前

すいません、自分ルールの説明してませんでした
Aはauxiliary(補助の)の略で、よく使うのと名前の通り補助的にしか使わないのでこうしてしまってます。

upDataは綴りミスでした。
upDateですね。
up+dataだと思い込んでました。

アバター
milfeulle
記事: 47
登録日時: 10年前
住所: マリーランド
連絡を取る:

Re: メンバ関数ポインタにメンバ関数のアドレスを代入したい

#6

投稿記事 by milfeulle » 10年前

オフトピック
newするのは確かに遅いのですが、人間が把握する程度の敵の数だったらほとんど気にならないと思います。もしかしたら考えすぎではないでしょうか!? (ちなみに、newするごとにメンバ関数が(動的に)量産されるというのは聞いたことがありません……。 )

素直にポリモーフィズムを用いた方が使い勝手もよく、分かりやすいような気がしますがいかがでしょうか……。

コード:

class Enemy {
public:
	virtual ~Enemy() { }
	virtual void draw() = 0;
	virtual void update() = 0;

protected:
	Enemy(float x, float y, float r, float hp) :
		is_live(true), counter(0), x(x), y(y), r(r), hp(hp) { }
	
	Enemy* next;
	Enemy* prev;

	float x, y, r, hp;
	int counter;
	bool is_live;
};

class EnemyZAC : public Enemy {
public:
	EnemyZAC(float x, float y) :
		Enemy(x, y, 16, 60) { }

	virtual void draw() {
		// drawZAC
	}
	virtual void update() {
		// updateZAC
	}
};
ζ*'ヮ')ζプログラミングはみんなで奏でるシンフォニー

ISLe
記事: 2650
登録日時: 13年前
連絡を取る:

Re: メンバ関数ポインタにメンバ関数のアドレスを代入したい

#7

投稿記事 by ISLe » 10年前

弾幕シューティングが代表するような大量にキャラが発生・消滅を繰り返すゲームプログラムでは、メモリ割り当てによる速度低下が問題になるというのはわりと有名なテーマですね。

ゲームの場合、メンバの各塊を共用体でメモリ確保しておいて、Strategyパターンを使って処理するのが最適ではないかと思います。
メンバへのアクセスは面倒臭くなりますが。

ちなみにnew演算子をオーバーライドして事前に確保しておいたメモリに割り当てるようにすれば、new演算子やクラスとしての使い勝手そのままに、メモリ割り当てのコストだけを削減することもできます。

『メモリプール』のキーワードでネット検索するといろんなサンプルや情報が見付かると思います。

nam

Re: メンバ関数ポインタにメンバ関数のアドレスを代入したい

#8

投稿記事 by nam » 10年前

milfeulleさんへ
今回作っているゲームがまさに問題となる弾幕シューティングなので見過ごせないのです。

ISLeさんへ
Strategyパターンですか…
なかなかに難しそうですね。

new演算子の乗っ取りは話題としては知っているのですがなかなか手を出せないままでいました。
これを機に試しに使ってみようかと思います。

皆様ありがとうございました。

閉鎖

“C言語何でも質問掲示板” へ戻る