派生クラスで関数ポインタを使うとうまくビルドできません

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
おやさい
記事: 2
登録日時: 9年前

派生クラスで関数ポインタを使うとうまくビルドできません

#1

投稿記事 by おやさい » 9年前

  今、ボタンを作っています。
  種類の違うボタンの処理をつくるのに、クラスを使うと同じ処理部分を省略できて楽だと知り
  初めてクラスを使ってみた状況です。

  ベースのボタンクラスを作り、新しいクラスに継承させて、
  処理を変更させたい関数を、オーバーライドし、処理の部分を変えました。
  それを関数ポインタを使って処理させたいのですが
  うまくビルドできません。

  簡単なプログラムにしてやってみたのですが、
  関数ポインタの所がうまくいってないようです。

コード:

#include "DxLib.h"

class base
{
	public:
		void (base::*func[2])();// 関数ポインタ

		base();// コンストラクタ

		virtual void a1();
		virtual void a2();

		void b( int i);
};

base::base()
{
	func[0] = &base::a1;
	func[1] = &base::a2;
}

void base::a1()
{
	DrawFormatString(100, 100,GetColor(255,255,255), "0" );	
}

void base::a2()
{
	DrawFormatString(100, 100,GetColor(255,255,255), "1" );	
}

void base::b( int i)
{
	if(i==0 || i==1)
	{
		(this->*func[i])();	
	}
}

}

	(this->*func[i])();
}


int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
    ChangeWindowMode(TRUE);//ウィンドウモード
    if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化

	//--- ▼ 前処理 ▼ ---


	SetDrawScreen( DX_SCREEN_BACK );//描画先を裏画面に設定

	base base1;


    while(ProcessMessage()==0 && ClearDrawScreen()==0)
	{
          //↑メッセージ処理          ↑画面をクリア           ↑入力状態を保存       ↑ESCが押されていない
  
		//--- ▼ ココから ▼ ---

		base1.b(1);
		

		ScreenFlip();//裏画面を表画面に反映 


		//--- ▲ ココまで ▲ ---
    }
 
    DxLib_End();
    return 0;
}

これでビルドをすると思ったとおりに実行されるのですが、
このクラスbaseを継承させた派生クラスbを作って、
上位のクラスbaseから継承してきたメソッドを再定義してビルドをするとできません。

コード:

#include "DxLib.h"

class base
{
	public:
		void (base::*func[2])();// 関数ポインタ

		base();// コンストラクタ
                  /////////////////////////
		virtual void a1();// virtual を追加
		virtual void a2();
                                        /////////////////////////
		void b( int i);
};

base::base()
{
	func[0] = &base::a1;
	func[1] = &base::a2;
}

void base::a1()
{
	DrawFormatString(100, 100,GetColor(255,255,255), "0" );	
}

void base::a2()
{
	DrawFormatString(100, 100,GetColor(255,255,255), "1" );	
}

void base::b( int i)
{
	if(i==0 || i==1)
	{
		(this->*func[i])();	
	}
}


///////////////////////////////////////////
//↓ 追加した所
///////////////////////////////////////////

class test :public base
{
	public:

		test();// コンストラクタ
		void a1();
		void a2();
};

test::test()
{
	func[0] = &test::a1;
	func[1] = &test::a2;
}

void test::a1()
{
	DrawFormatString(100, 100,GetColor(255,255,255), "3" );	
}

void test::a2()
{
	DrawFormatString(100, 100,GetColor(255,255,255), "4" );	
}


///////////////////////////////////////////
//↑ 追加した所
///////////////////////////////////////////


int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
    ChangeWindowMode(TRUE);//ウィンドウモード
    if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化

	//--- ▼ 前処理 ▼ ---


	SetDrawScreen( DX_SCREEN_BACK );//描画先を裏画面に設定

	test test1;


    while(ProcessMessage()==0 && ClearDrawScreen()==0)
	{
          //↑メッセージ処理          ↑画面をクリア           ↑入力状態を保存       ↑ESCが押されていない
  
		//--- ▼ ココから ▼ ---

		test1.b(1);
		

		ScreenFlip();//裏画面を表画面に反映 


		//--- ▲ ココまで ▲ ---
    }
 
    DxLib_End();
    return 0;
}

コード:

test::test()
{
	func[0] = &test::a1;
	func[1] = &test::a2;
}
のところがうまくいっていないようなのですが
うまく関数ポインタを使って、派生クラスtestのa1と、a2
の処理ができるようにしたいです。

派生クラスで関数ポインタを使い、オーバーライドした関数を使う方法、
派生クラスの関数ポインタの使い方が調べてもよくわからないので教えて欲しいです。

よろしくお願いします。

アバター
h2so5
副管理人
記事: 2212
登録日時: 13年前
住所: 東京
連絡を取る:

Re: 派生クラスで関数ポインタを使うとうまくビルドできません

#2

投稿記事 by h2so5 » 9年前

無理に処理を共通化しようとするとややこしくなるだけなので止めたほうがよいです。

hoge

Re: 派生クラスで関数ポインタを使うとうまくビルドできません

#3

投稿記事 by hoge » 9年前

コード:

test::test()
{
    func[0] = &test::a1;
    func[1] = &test::a2;
}
この部分が全部不要です。
これを削除してもa1,a2は仮想関数なので派生クラスでオーバライドした関数が呼ばれます。

アバター
h2so5
副管理人
記事: 2212
登録日時: 13年前
住所: 東京
連絡を取る:

Re: 派生クラスで関数ポインタを使うとうまくビルドできません

#4

投稿記事 by h2so5 » 9年前

関数ポインタによるディスパッチを行いたい場合は、void b(int i) をオーバーライドするべきです。

コード:

class base
{
public:
    base();
    virtual void b(int i);
    
private:
    void a1();
    void a2();
};

base::base()
{
}

void base::a1()
{
    DrawFormatString(100, 100,GetColor(255,255,255), "0" );
}

void base::a2()
{
    DrawFormatString(100, 100,GetColor(255,255,255), "1" );
}

void base::b(int i)
{
    static void (base::* const func[2])() = {
        &base::a1,
        &base::a2
    };
    
    if(i==0 || i==1)
    {
        (this->*func[i])();
    }
}

class test : public base
{
public:
    test();
    void b(int i);

private:
    void a1();
    void a2();
};

test::test()
{
}

void test::a1()
{
    DrawFormatString(100, 100,GetColor(255,255,255), "3" );
}

void test::a2()
{
    DrawFormatString(100, 100,GetColor(255,255,255), "4" );
}

void test::b(int i)
{
    static void (test::* const func[2])() = {
        &test::a1,
        &test::a2
    };
    
    if(i==0 || i==1)
    {
        (this->*func[i])();
    }
}

おやさい
記事: 2
登録日時: 9年前

Re: 派生クラスで関数ポインタを使うとうまくビルドできません

#5

投稿記事 by おやさい » 9年前

hoge さんが書きました:

コード:

test::test()
{
    func[0] = &test::a1;
    func[1] = &test::a2;
}
この部分が全部不要です。
これを削除してもa1,a2は仮想関数なので派生クラスでオーバライドした関数が呼ばれます。
コンストラクタに同じ処理を書かなくても、オーバーライドしてくれるのですね。
勉強になりました。
ありがとうございます。
h2so5 さんが書きました:無理に処理を共通化しようとするとややこしくなるだけなので止めたほうがよいです。
使うときに簡単に使えるようなプログラムを作ろうと思っていました。
が、無理に共通化してしまっていたようで、そうするとややこしくなってしまうようですね。
プログラムを作ったり修正したりするときにややこしいっていうのも問題なので
改めてどういうプログラムにするか考えなおしてみようと思います。
ありがとうございます。
h2so5 さんが書きました: 関数ポインタによるディスパッチを行いたい場合は、void b(int i) をオーバーライドするべきです。

コード:

class base
{
public:
    base();
    virtual void b(int i);
    
private:
    void a1();
    void a2();
};

base::base()
{
}

void base::a1()
{
    DrawFormatString(100, 100,GetColor(255,255,255), "0" );
}

void base::a2()
{
    DrawFormatString(100, 100,GetColor(255,255,255), "1" );
}

void base::b(int i)
{
    static void (base::* const func[2])() = {
        &base::a1,
        &base::a2
    };
    
    if(i==0 || i==1)
    {
        (this->*func[i])();
    }
}

class test : public base
{
public:
    test();
    void b(int i);

private:
    void a1();
    void a2();
};

test::test()
{
}

void test::a1()
{
    DrawFormatString(100, 100,GetColor(255,255,255), "3" );
}

void test::a2()
{
    DrawFormatString(100, 100,GetColor(255,255,255), "4" );
}

void test::b(int i)
{
    static void (test::* const func[2])() = {
        &test::a1,
        &test::a2
    };
    
    if(i==0 || i==1)
    {
        (this->*func[i])();
    }
}
b関数の静的変数として、関数ポインタをこう使うとうまくいくんですね。
自分では考えつきませんでした。
とても分かりやすく、ビルドしてみたら無事できました。

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

閉鎖

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