コールバックについて – プログラミング – Home

通知
すべてクリア

[解決済] コールバックについて

固定ページ 1 / 2

+
 +
(@ )
ゲスト
結合: 17年前
投稿: 50
Topic starter  

C/C++問題の気がするが、VC7.0でWinXPなのでここに質問です。

以下のソース例で、BクラスからAクラス(複数)のコールバックを呼んだ際に
目的のAクラスと違うインスタンスを指す時があり困っています。

ソース例では25番目を指定しますが、これが18番目になったりします。

typedef void(__stdcall *CallBack)(int) ;

class A
{
public:
A(void);
virtual ~A(void);
static void __stdcall Function(int id){ TRACE( %X , this ); }
};

class B
{
public:
B(void);
virtual ~B(void);
void Set( int id , CallBack p ){m_ID=id; m_CallBack=p}
void Execute(){ (*m_CallBack)(m_ID) ; }
protected:
int m_ID ;
CallBack m_CallBack ;
};

int main()
{
A tmpA[50] ;
B tmpB ;

tmpB.Set( 100 , tmpA[25].Function ) ;
tmpB.Execute() ;
}


引用未解決
トピックタグ
+
 +
(@ )
ゲスト
結合: 17年前
投稿: 50
Topic starter  

すこし間違い。
int main()
{
A *tmpA = new A [50] ;
B tmpB ;

tmpB.Set( 100 , (*tmpA)[25].Function ) ;
tmpB.Execute() ;
}


返信引用
aetos
(@aetos)
Noble Member
結合: 5年前
投稿: 1480
 

static 関数の中で this 参照できるん?


返信引用
επιστημη
 επιστημη
(@επιστημη)
ゲスト
結合: 22年前
投稿: 1301
 

> static void __stdcall Function(int id){ TRACE( %X , this ); }

staticメンバ関数がthisを参照できっこないんですけど...


返信引用
επιστημη
 επιστημη
(@επιστημη)
ゲスト
結合: 22年前
投稿: 1301
 

ぁぅ、モロかぶり orz


返信引用
+
 +
(@ )
ゲスト
結合: 17年前
投稿: 50
Topic starter  

すみません。
あまり関係ないかな?と省略してました(^^;

class A
{
(略)
protected:
static A *thisPointer ;
};

A *A::thisPointer = NULL ;
A::A(void)
{
A::thisPointer = this ;
}

void __stdcall A::Function(int id)
{
TRACE( %X , A::thisPointer );
}

です。


返信引用
YuO
 YuO
(@YuO)
ゲスト
結合: 22年前
投稿: 320
 

staticはクラスで共有されることを理解していますか?
クラスAで最後にコンストラクタが呼び出されたインスタンスへのポインタ
が,thisPointerに保持されますよ。


返信引用
Blue
 Blue
(@Blue)
ゲスト
結合: 20年前
投稿: 1467
 

>A::Function(int id)
idってのがまた関連していそうだけど、、、

こんなことをやりたいのかと想像してみる。

#include <map>
#include <cstdio>

class A
{
static std::map<int, A*> m_list;

int m_id;
public:
A()
{
this->m_id = m_list.size();
m_list[this->m_id] = this;
}

int GetID() const { return this->m_id; }
void Print() const { printf(%d : %p\n, this->m_id, (void*)this); }

static A* GetPointer(const int id)
{
std::map<int, A*>::iterator it = m_list.find(id);
if (it != m_list.end())
return it->second;
return NULL;
}
};

std::map<int, A*> A::m_list;

int main()
{
A a1, a2, a3;
A* p;

printf(%p\n, &a1);
p = A::GetPointer(a1.GetID());
p->Print();

printf(%p\n, &a2);
p = A::GetPointer(a2.GetID());
p->Print();

printf(%p\n, &a3);
p = A::GetPointer(a3.GetID());
p->Print();

return 0;
}


返信引用
PATIO
(@patio)
Famed Member
結合: 3年前
投稿: 2660
 

そもそも、staticなメンバー関数はクラスインスタンス無しで呼べて
かつ、クラスのメンバー変数にアクセスできないわけですから
インスタンス毎に呼び分けても意味が無いのではないかなぁ。

typedef void(__stdcall *CallBack)(int, A*);

static void __stdcall Function(int id, A* pa);
とかしてその都度インスタンスを渡すならわからなくはないですけどね。

class B
{
public:
B(void);
virtual ~B(void);
void Set( int id , CallBack p, A* pa){m_ID=id; m_CallBack=p; m_pa=pa;}
void Execute(){ (*m_CallBack)(m_ID) ; }
protected:
int m_ID ;
A* m_pa
CallBack m_CallBack ;
};

tmpB.Set( 100 , A::Function, &tmpA[25] );

とか。
何がやりたくてこういう事をしているのかまで書くと
もっと色々レスがつくと思いますよ。


返信引用
Blue
 Blue
(@Blue)
ゲスト
結合: 20年前
投稿: 1467
 

あ、削除に関してまったく考慮していなかったです。

デストラクタでリストから削除しないとだめですね。
ということでIDの振り方も問題ありです。


返信引用
PATIO
(@patio)
Famed Member
結合: 3年前
投稿: 2660
 

ごめん、ここ修正。

void Execute(){ (*m_CallBack)(m_ID, m_pa) ; }

動くかどうかの検証はしていないので参考程度に。


返信引用
Kerry
 Kerry
(@Kerry)
ゲスト
結合: 20年前
投稿: 192
 

こうすればどうだろうか? 同じことではあるが…

class A
{
public:
void Function(int id)
{}
};

typedef void (A::*Callback)(int);

class B
{
public:
void Set(int id, Callback p, A* pa)
{
m_ID = id;
m_Callback = p;
m_pa = pa;
}
void Execute()
{
(m_pa->*m_Callback)(m_ID);
}

protected:
int m_ID;
A* m_pa;
Callback m_Callback;
};

tmpB.Set(100, &A::Function, &tmpA[25]);


返信引用
+
 +
(@ )
ゲスト
結合: 17年前
投稿: 50
Topic starter  

レスありがとうございます。
Blue氏提示の方法に変更できるのか、ソースとにらめっこしてました。

>なにがやりたいのか。
まず質問の経緯です。
・classAと、classBは参照関係が全く無い。
・が、classBの状態変化を、特定のclassAインスタンスへ通知する必要がでてきた。
・でもclassAと、classBは結び付けたくない。
・そこでAも、Bも知ってる人(掲題ソースではmain)を新たに作って必要な関数だけを
登録。

と考え、修正してみたのですがバグにはまった次第です。
classBから直接、classAの関数呼んでまうのが簡単ですが、コールバックで実現できな
いかな。
などと欲張ったあたりが敗因?


返信引用
subaru
 subaru
(@subaru)
ゲスト
結合: 19年前
投稿: 381
 

Observerパターンでもいいと思います。

class Callback
{
public:
Callback() {}
virtual ~Callback() {}
virtual void Function(int id) = 0;
};

class A : public Callback
{
public:
A() {}
virtual ~A() {}
private:
void Function(int id) { TRACE( %X , this ); }
};

class B
{
public:
B() : m_ID(0), m_CallBack(NULL) {}
virtual ~B() {}
void Set(int id, Callback* p) { m_ID=id; m_CallBack=p; }
void Execute() { if(m_CallBack) m_CallBack->Function(m_ID); }
private:
int m_ID ;
Callback* m_CallBack ;
};

int main()
{
A tmpA[50] ;
B tmpB ;

tmpB.Set( 100 , &tmpA[25] ) ;
tmpB.Execute() ;
}


返信引用
PATIO
(@patio)
Famed Member
結合: 3年前
投稿: 2660
 

subaruさんのが一番素直かなぁ。
私もこの方法に一票。
class Bがclass Aをまったく知らないと言うのは無理があると思いますよ。
せめて親の型くらいは知っていないと呼び出せませんし。


返信引用
固定ページ 1 / 2

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました