メンバ関数ポインタの仕様がわかりません。

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

メンバ関数ポインタの仕様がわかりません。

#1

投稿記事 by いせすげr » 7年前

カードゲームを作りたいので、コンソールで内部の仮動作を確認するために制作中です。
スーパークラスを継承したメンバ関数を、同じスーパークラスを継承したメンバ関数ポインタにいれたいのですがうまくいきません。
このような形で実装してみたいのですが、どうすればいいのでしょうか?
そもそも無理なのでしょうか?

コード:

Source.cpp
#include<stdio.h>
#include<vector>

using namespace std;

#include"Header.h"

/////////////////////////////////////
// Cardの基礎部分

void cCard::AddToAbility(CardGrant tes)
{
	this->Grant.push_back(tes);
}

void cCard::Preparition()
{
	for (auto v : Grant)
	{
		v;
	}
}

void cCard::Test()
{
	printf("%d", this->hp);
}


/////////////////////////////////////
// メインループ!

int main()
{
	cMonster1 mons1;
	cMonster2 mons2;

	// モンスター1号の能力を発動!ここでerror C2276
	mons2.AddToAbility(&mons1.Ability);

	// モンスター2号の処理
	mons2.Preparition();

	// モンスター2号のhp表示
	mons2.Test();

	while (1);

}

コード:

Header.h
#pragma once

class cCard;

typedef void (cCard::*CardGrant)();				// たぶんこれが問題だと思ってます。

class cCard
{
public:
	
	cCard():hp(1) {};					// カードの初期化
	virtual ~cCard() {};

	virtual void Ability() {};			// このカードの能力
	void AddToAbility(CardGrant);		// 能力を受けた
	void Preparition();					// このカードに受けた効果を処理する
	void Test();						// hpを表示する

protected:
	struct 
	{// カードの中身
		int hp;

	};
	vector<CardGrant> Grant;			// このカードにかかってる付与効果
};

////////////////////////////////////////////
// ここからカードの中身について書いてくよ!

class cMonster1 : public cCard
{// モンスター1号!
	void Ability() { this->hp -= 1; };	// hpを0にしたい!
};

class cMonster2 : public cCard
{// モンスター2号!

};

かずま

Re: メンバ関数ポインタの仕様がわかりません。

#2

投稿記事 by かずま » 7年前

- Header.h の 34 行目に public: を追加する
- Source.cpp の 40行目を次のようにする
 mons2.AddToAbility(reinterpret_cast<CardGrant>(&cMonster1::Ability));
これでコンパイルエラーはなくなります。

cMonster1::Ability は、自分の hp を 1減らす機能ですね。

mons2.AddToAbility(reinterpret_cast<CardGrant>(&cMonster1::Ability));
の実行で、mons2 の Grant に cMonster1::Ability
という「メンバ関数」を登録できました。
mons2 が mons1 の能力を獲得したつもりですね。

しかし、mons2.Preparition(); では
登録状況の確認だけで、何も実行していません。
登録したメンバ関数を実行していないのです。

mons2.Test(); では、何も変更されていない mons2 の
hp を表示して、それは 1 です。

では、Preparition() で、登録したメンバ関数を
実行すればよいということになります。そこで

コード:

void cCard::Preparition()
{
	for (auto v : Grant)
		(this->*v)();
}
mons2.Preparition(); で呼び出すと、this は mons2 を
指していますから mons2 の hp が 1 減りそうです。
ところが、this が mons2 を指しているので、this->*v は
cMonster2::Ability です。cMonster2 は Ability を
オーバーライドしていないので cCard::Ability が呼び出され、
結局何もしません。

かずま

Re: メンバ関数ポインタの仕様がわかりません。

#3

投稿記事 by かずま » 7年前

こうすれば、hp が 0 になりますが、いかがでしょうか?

コード:

//Header.h
#pragma once
 
class cCard;
 
typedef void (cCard::*CardGrant)(cCard *);  // 引数を追加
 
class cCard
{
public:
    cCard():hp(1) {};                   // カードの初期化
    virtual ~cCard() {};
 
    virtual void Ability(cCard *) {};   // このカードの能力
    void AddToAbility(CardGrant);       // 能力を受けた
    void Preparition(cCard *);          // このカードに受けた効果を処理する
    void Test();                        // hpを表示する
    void PowerDown() { hp--; }          // hp を減らす
 
protected:
    struct 
    {// カードの中身
        int hp;
    };
    vector<CardGrant> Grant;            // このカードにかかってる付与効果
};
 
////////////////////////////////////////////
// ここからカードの中身について書いてくよ!
 
class cMonster1 : public cCard
{// モンスター1号!
public:
    void Ability(cCard *card) { card->PowerDown(); };  // hpを0にしたい!
};
 
class cMonster2 : public cCard
{// モンスター2号!
 
};

コード:

//Source.cpp
#include<stdio.h>
#include<vector>
 
using namespace std;
 
#include"Header.h"
 
/////////////////////////////////////
// Cardの基礎部分
 
void cCard::AddToAbility(CardGrant tes)
{
    this->Grant.push_back(tes);
}
 
void cCard::Preparition(cCard *card)
{
    for (auto v : Grant)
    {
        (card->*v)(this);
    }
}
 
void cCard::Test()
{
    printf("%d\n", this->hp);
}
 
 
/////////////////////////////////////
// メインループ!
 
int main()
{
    cMonster1 mons1;
    cMonster2 mons2;
 
    // モンスター1号の能力を発動!ここでerror C2276
    mons2.AddToAbility(reinterpret_cast<CardGrant>(&cMonster1::Ability));
 
    // モンスター2号の処理
    mons2.Preparition(&mons1);
 
    // モンスター2号のhp表示
    mons2.Test();
 
    while (1);
 
}
while (1); は感心しません。getchar(); でいいのでは?

いせすげr

Re: メンバ関数ポインタの仕様がわかりません。

#4

投稿記事 by いせすげr » 7年前

かずまさんへ
少し自分が思っていた方法と違っていることと、自分が思っていた方法は実現できないことを知ったので別の方法を探してみようと思います。
本当にありがとうございました!

返信

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