随笔-3  评论-5  文章-13  trackbacks-0

--------------------------------------------------------------------------------
标题: 如何使用类的成员方法指针?
作者: 叶飞虎
日期: 2009.03.22
--------------------------------------------------------------------------------

   其实,类方法调用原理很简单,若知道如何使用C语言模拟类实现就知道怎么回事了,只
是这个工作由编译器来做罢了。调用方法与调用函数的区别是在调用方法时,编译器把当前
对象的指针当做第一个参数传入,其它参数的传递与函数没有区别,也就说,这为提供回调
事件的方法指针提供一条方便之门。方法指针不能滥用,用好它可以使你的视野更加开阔!

  1 /* TObject - 基类 */
  2 
  3 class TObject
  4 {
  5 };
  6 
  7 
  8 /* TDemoA - A 类 */
  9 
 10 class TDemoA
 11 {
 12 public:
 13    TDemoA();
 14    virtual ~TDemoA();
 15 
 16    void  AF1(void* AParam);
 17    void  AF2(const char* AStr, long AValue);
 18 
 19    // ???  
 20 };
 21 
 22 /* TDemoB - B 类 */
 23 
 24 class TDemoB
 25 {
 26 public:
 27    TDemoB();
 28    virtual ~TDemoB();
 29 
 30    void  BF1(void* AParam);
 31    void  BF2(const char* AStr, long AValue);
 32 
 33    // ???  
 34 };
 35 
 36 /* TDemoC - C 类 */
 37 
 38 class TDemoC
 39 {
 40 public:
 41    // TOnFunc1 事件类型
 42    typedef void (TObject::*TDoFunc1)(void* AParam);
 43    typedef struct
 44    {
 45       TDoFunc1          Method;
 46       void*             Object;
 47    } TOnFunc1;
 48 
 49    // TOnFunc2 事件类型
 50    typedef void (TObject::*TDoFunc2)(const char* AStr, long AValue);
 51    typedef struct
 52    {
 53       TDoFunc2          Method;
 54       void*             Object;
 55    } TOnFunc2;
 56 
 57 public:
 58    TDemoC();
 59    virtual ~TDemoC();
 60 
 61    // Func1
 62    void  Func1(void* AParam)
 63    {
 64       if (OnFunc1.Method != NULL)
 65          ((TObject*)OnFunc1.Object->*OnFunc1.Method)(AParam);
 66    }
 67 
 68    // Func2
 69    void  Func2(const char* AStr, long AValue)
 70    {
 71       if (OnFunc2.Method != NULL)
 72          ((TObject*)OnFunc2.Object->*OnFunc2.Method)(AStr, AValue);
 73    }
 74 
 75    // 事件
 76    TOnFunc1    OnFunc1;
 77    TOnFunc1    OnFunc2;
 78 };
 79 
 80 
 81 // 例子
 82 TDemoA A;
 83 TDemoB B;
 84 TDemoC C;
 85 
 86 int demo()
 87 {
 88    // ???  
 89 
 90    C.OnFunc1.Object  = &B;
 91    C.OnFunc1.Method  = (TDemoC::TDoFunc1)&TDemoB::BF1;
 92 
 93    C.OnFunc2.Object  = &A;
 94    C.OnFunc2.Method  = (TDemoC::TDoFunc2)&TDemoA::AF2;
 95 
 96    // 调用 C 方法
 97    C.Func1();     // <=> B.BF1();
 98    C.Func2();     // <=> A.AF2();
 99 
100    // ???  
101 
102    C.OnFunc1.Object  = &A;
103    C.OnFunc1.Method  = (TDemoC::TDoFunc1)&TDemoA::AF1;
104 
105    C.OnFunc2.Object  = &B;
106    C.OnFunc2.Method  = (TDemoC::TDoFunc2)&TDemoB::BF2;
107 
108    // 调用 C 方法
109    C.Func1();     // <=> A.AF1();
110    C.Func2();     // <=> B.BF2();
111 
112    // ???  
113 
114 }
115 
116 /* TKYFmtMemEvent - 格式化内存项事件类 */
117 
118 class TKYFmtMemEvent
119 {
120 public:
121    // TOnFormat 事件类型
122    typedef void (TObject::*TDoFormat)(void* AItem, Word ASize);
123    typedef struct
124    {
125       TDoFormat         Method;
126       void*             Object;
127    } TOnFormat;
128 
129 public:
130    TKYFmtMemEvent()  { Clear(); }
131    ~TKYFmtMemEvent() { Clear(); }
132 
133    // 清除
134    void  Clear();
135 
136    // 执行 OnInitialize 事件
137    void  DoInitialize(void* AItem, Word ASize)
138    {
139       if (OnInitialize.Method != NULL)
140          ((TObject*)OnInitialize.Object->*OnInitialize.Method)(AItem, ASize);
141    }
142 
143    // 执行 OnFinalize 事件
144    void  DoFinalize(void* AItem, Word ASize)
145    {
146       if (OnFinalize.Method != NULL)
147          ((TObject*)OnFinalize.Object->*OnFinalize.Method)(AItem, ASize);
148    }
149 
150    // 事件
151    TOnFormat   OnInitialize;
152    TOnFormat   OnFinalize;
153 
154 protected:
155 private:
156 };
157 
158 // 例子:如何设置事件方法指针
159 void TDemo::SetEvent()
160 {
161    FDemo.OnInitialize.Object = this;
162    FDemo.OnInitialize.Method = (TKYFmtMemEvent::TDoFormat)&TDemo::DoFormat;
163 
164    // ???  
165 }
166 
167 // FDemo 的 OnInitialize 事件方法
168 void TDemo::DoFormat(void* AItem, Word ASize)
169 {
170    // ???  
171 }
172 


    回调事件的方法指针需要C++编译器支持,至少VC的不同版本及GCC编译器都支持。
在VC6和VC2003中设置方法指针相对较宽松,VC2005之后就很严格了,如下:
FDemo.OnInitialize.Method = (TKYFmtMemEvent::TDoFormat)&TDemo::DoFormat;

   这行代码都被不同版本VC编译器支持,但如下代码就只能被VC6、VC2003支持:
FDemo.OnInitialize.Method = (TKYFmtMemEvent::TDoFormat)DoFormat;

   其实,类方法调用原理很简单,若知道如何使用C语言模拟类实现就知道怎么回事了,只
是这个工作由编译器来做罢了。不过不是什么方法都可以调用的,如:静态方法就只能当做
函数指针来用,而重载方法、虚方法等等是不可靠的,所以最好使用普通的类方法指针。

   调用方法与调用函数的区别是在调用方法时,编译器把当前对象的指针当做第一个参数传
入,其它参数的传递与函数没有区别,也就说,这为提供回调事件的方法指针提供一条方便之门。

   方法指针不能滥用,用好它可以使你的视野更加开阔!



posted on 2011-05-22 11:01 Kyee Ye 阅读(377) 评论(0)  编辑 收藏 引用 所属分类: 技巧杂集

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理