今天在写cocos2d-x游戏的时候,突然对cocos2d-x中回调机制很感兴趣,但是之前两周第一次接触实际C++开发,又要学习cocos2d-x框架,还有比较疲劳。实在没有心情去搞这些,这两天偷了个懒,缓了两天,终于又有精神干活了,要写大量的类似大掌门一样的战斗动画播放。我原来的想法是使用大量的回调来控制,因为不同的回合的动画需要的处理是不一样的,动画长短,还有后续的处理方式。后来发觉不现实,大量的回调,会把自己搞得头晕脑胀,根本无法控制流程,灵活性太低,最后决定使用定时去做。
话说回来,今天看到函数指针,突然很感兴趣,于是决定看看这一部分的知识,看看在CCObject中的关于schedule指针的定义
- typedef void (CCObject::*SEL_SCHEDULE)(float);
- #define schedule_selector(_SELECTOR) (SEL_SCHEDULE)(&_SELECTOR)
我得思路一直停留在C语言中的函数指针中,对于&符号的含义非常不清楚,这时候问一个经常使用C++的同学,他也表示很不清楚,大概是对C++的理解,停留在C语言的基础上,这样也有不好的一点,容易固化思维。我也是这样子的,对于传递一个这样一个指针的时候。
- void GameFightingLayer::performRoundAnimation(float time)
- this -> schedule(schedule_selector(GameFightingLayer::performAttackAnimation), delay);
可以发现,这个宏中传递函数指针的时候,需要添加GameFightingLayer作用域,对宏展开之后发现,其实&GameFightingLayer::performAttackAnimation。。。。基于对C语言的了解,不应该这样的,应该是直接GameFightingLayer::performAttackAnimation就是表示函数指针了,为什么还要加一个&符号呢?问同学,他也表示不了解,后来发现。这是一种C++中特有的语法类型。
http://www.parashift.com/c++-faq-lite/fnptr-vs-memfnptr-types.html
这个网站解释的很清楚:
Consider the following function:
int f(char a, float b);The type of this function is different depending on whether it is an ordinary function or a non- static member function of some class:
- Its type is "int (*)(char,float)" if an ordinary function
- Its type is "int (Fred::*)(char,float)" if a non-static member function of class Fred
Note: if it's a static member function of class Fred, its type is the same as if it were an ordinary function: "int (*)(char,float)".
根据成员方法指针是否是静态而言,如是静态方法,则其类型就可表示为与普通的方法指针相同,如果不是,那么这个方法指针的类型,就跟普通方法指针不一致了,是一种C++特有的语法,跟C不一致。同学跟我解释是,想想一下内存地址的就明白为什么这样了,也是,往往把基本都忘记,如果是静态的,地址空间是固定的,非静态的话,方法地址必定是跟某个class相关的。
后来又发现一个很有意思的问题,在使用这种指针的时候,编译器总是报错,后来偶尔间改了一下空格,发现好。。。。
错的写法: m_pSelectorTarget -> *m_pCallFunc
正确的写法: m_pSelectorTarget ->* m_pCallFunc
我习惯性地分割操作符,结果发现总是会有问题,原来->*和.*是操作符,坑爹啊!是C++中的操作符,已经不能按C中的指针的概念理解了。正如msdn中这篇文章的解释一样:
http://msdn.microsoft.com/en-us/library/k8336763.aspx
其中有一段代码我感觉挺有意思的,除了解释上面的问题之外,还有别的问题帮我解决了
- // expre_Expressions_with_Pointer_Member_Operators.cpp
- // compile with: /EHsc
- #include <iostream>
- using namespace std;
- class Testpm {
- public:
- void m_func1() { cout << "m_func1\n"; }
- int m_num;
- };
- // Define derived types pmfn and pmd.
- // These types are pointers to members m_func1() and
- // m_num, respectively.
- void (Testpm::*pmfn)() = &Testpm::m_func1;
- int Testpm::*pmd = &Testpm::m_num;
- int main() {
- Testpm ATestpm;
- Testpm *pTestpm = new Testpm;
- // Access the member function
- (ATestpm.*pmfn)();
- (pTestpm->*pmfn)(); // Parentheses required since * binds
- // less tightly than the function call.
- // Access the member data
- ATestpm.*pmd = 1;
- pTestpm->*pmd = 2;
- cout << ATestpm.*pmd << endl
- << pTestpm->*pmd << endl;
- delete pTestpm;
- }
这段代码中, 说明了->*和.*操作符的区别,正如结构体调用时的方式一样 。
还有一个比较有意思的地方就是,关于成员变量的指针,竟然跟操作成员函数的方式一样。
还有一些关于这个话题比较有意思的讨论,链接如下:
http://stackoverflow.com/questions/2891926/create-thread-is-not-accepting-the-member-function
http://www.parashift.com/c++-faq-lite/memfnptr-vs-fnptr.html