zoukankan      html  css  js  c++  java
  • 类成员函数指针 ->*语法剖析

    在cocos2d-x中,经常会出现这样的调用,如 ->*,这个是什么意思呢,如下面得这个例子:

    其实这是对类的成员函数指针的调用,在cocos2dx中,这种形式多用于回调函数的调用。如我们经常用到的循环函数

    schedule( CC_SCHEDULE_SELECTOR(PauseTest::unpause), 3); 

    这个意思就是每隔3秒,执行一下unpause方法,这里就用到了成员函数指针,先看下CC_SCHEDULE_SELECTOR的宏定义

    #define CC_SCHEDULE_SELECTOR(_SELECTOR) static_cast<cocos2d::SEL_SCHEDULE>(&_SELECTOR)

    就是把传入的函数,然后取其地址,转换为 SEL_SCHEDULE,那么SEL_SCHEDULE是什么呢,转到其定义处,为

    typedef void (Ref::*SEL_SCHEDULE)(float);

    就是说他就是一个指向参数为float,返回值为void 的函数指针,注意他和一般c语言的函数指针不同的是,前面加了作用域Ref,在后面会讲解一般函数指针和类函数指针的不同,这里先看作用域为什么是Ref,以为cocos2d所有的类都继承自Ref,所以只要是cocos2d的类,就可以作为SEL_SCHEDULE的target,深入到scheduleCC_SCHEDULE_SELECTOR(PauseTest::unpause), 3); 的里面,就会发现,是这么调用的

    ,_selector就是回到函数的地址,_target就是要调用这个回调函数的基类为Ref的对象指针,当每次循环的时候,就会这么调用

    从而实现了指定的target进行函数的回调.

    现在用一个demo简单演示一下他的用法

     

    namespace AB {
    class A ;
    typedef void (A::*SEL_CallJinLei)();
    class A
    {
    public:
        A(){}
        virtual  void  testA();
    };
    
    void A::testA(){
         printf("A的testA");
    }
    
    class ChildrenA: public A{
    public:
      virtual  void  testA(){
          printf("ChildrenA的testA");
        }
    };
    class B
    {
      public:
         B(){
         }
        B(A*target,SEL_CallJinLei selector){
            _target=target;
            _selector=selector;
            
        }
        A *_target;
        SEL_CallJinLei _selector;
        void testB(){
          (_target->*_selector)();
        }
        
    };
    }
    void main(){
    
     using namespace AB;
        AB::A *aaa=new A();
        ChildrenA *aaa2=new ChildrenA();
        B *bbb=new B(aaa,static_cast<AB::SEL_CallJinLei>(&A::testA));
        bbb->testB();
        B *bbb2=new B(aaa2,static_cast<AB::SEL_CallJinLei>(&ChildrenA::testA));
        bbb2->testB();
    }
    

     Class A和Class ChildrenA都是我们指的target,他们有成员函数指针,当确定了函数指针的指向,就可以用target来调用了,

    通过main中的调用也可以看出, Class A和Class ChildrenA都可以使用 

    SEL_CallJinLei,也就是实现了多态特性


    在cocos2dx中应用也就是 testB就是执行了某些逻辑之后,触发的方法,如scheduler中的trigger,触发之后,就会调用target->*函数指针,从而实现了target的回调方法


    下面是解释一般函数指针和成员函数指针的区别,这个网上也比较多了,这里引用一篇,

    原文地址为http://www.jb51.net/article/40718.htm

     

    函数指针是通过指向函数的指针间接调用函数。函数指针可以实现对参数类型、参数顺序、返回值都相同的函数进行封装,是多态的一种实现方式。由于类的非静态成员函数中有一个隐形的this指针,因此,类的成员函数的指针和一般函数的指针的表现形式不一样。

    1、指向一般函数的指针
    函数指针的声明中就包括了函数的参数类型、顺序和返回值,只能把相匹配的函数地址赋值给函数指针。为了封装同类型的函数,可以把函数指针作为通用接口函数的参数,并通过函数指针来间接调用所封装的函数。
    下面是一个指向函数的指针使用的例子。

    复制代码代码如下:

    #include <iostream.h>
    /*指向函数的指针*/
    typedef int (*pFun)(int, int);
    int Max(int a, int b)
    {
        return a > b ? a : b;
    }
    int Min(int a, int b)
    {
        return a < b ? a : b;
    }
    /*通用接口函数,实现对其他函数的封装*/
    int Result(pFun fun, int a, int b)
    {
        return (*fun)(a, b);
    }
    void main()
    {
        int a = 3;
        int b = 4;
        cout<<"Test function pointer: "<<endl;
        cout<<"The maximum number between a and b is "<<Result(Max, a, b)<<endl;
        cout<<"The minimum number between a and b is "<<Result(Min, a, b)<<endl;
    }


    2、指向类的成员函数的指针
    类的静态成员函数采用与一般函数指针相同的调用方式,而受this指针的影响,类的非静态成员函数与一般函数指针是不兼容的。而且,不同类的this指针是不一样的,因此,指向不同类的非静态成员函数的指针也是不兼容的。指向类的非静态成员函数的指针,在声明时就需要添加类名。

    下面是一个指向类的成员函数的指针的使用的例子,包括指向静态和非静态成员函数的指针的使用。

    复制代码代码如下:

    #include <iostream.h>

        class CA;

        /*指向类的非静态成员函数的指针*/
        typedef int (CA::*pClassFun)(int, int);

        /*指向一般函数的指针*/
        typedef int (*pGeneralFun)(int, int);

        class CA
        {
        public:

            int Max(int a, int b)
            {
                return a > b ? a : b;
            }

            int Min(int a, int b)
            {
                return a < b ? a : b;
            }

            static int Sum(int a, int b)
            {
                return a + b;
            }

            /*类内部的接口函数,实现对类的非静态成员函数的封装*/
            int Result(pClassFun fun, int a, int b)
            {
                return (this->*fun)(a, b);
            }

        };

        /*类外部的接口函数,实现对类的非静态成员函数的封装*/
        int Result(CA* pA, pClassFun fun, int a, int b)
        {
            return (pA->*fun)(a, b);
        }

        /*类外部的接口函数,实现对类的静态成员函数的封装*/
        int GeneralResult(pGeneralFun fun, int a, int b)
        {
            return (*fun)(a, b);
        }

        
        void main()
        {
            CA ca;
            int a = 3;
            int b = 4;

            cout<<"Test nonstatic member function pointer from member function:"<<endl;
            cout<<"The maximum number between a and b is "<<ca.Result(CA::Max, a, b)<<endl;
            cout<<"The minimum number between a and b is "<<ca.Result(CA::Min, a, b)<<endl;

            cout<<endl;
            cout<<"Test nonstatic member function pointer from external function:"<<endl;
            cout<<"The maximum number between a and b is "<<Result(&ca, CA::Max, a, b)<<endl;
            cout<<"The minimum number between a and b is "<<Result(&ca, CA::Min, a, b)<<endl;

            cout<<endl;
            cout<<"Test static member function pointer: "<<endl;
            cout<<"The sum of a and b is "<<GeneralResult(CA::Sum, a, b)<<endl;
        }

     

     

     

     

     

  • 相关阅读:
    02020_正则表达式练习
    SSM框架——以注解形式实现事务管理
    Spring + Mybatis 使用 PageHelper 插件分页
    使用Mozilla Firefox插件RestClient测试Http API接口
    Maven学习 (四) 使用Nexus搭建Maven私服
    BigDecimal类型比较大小
    Mybatis 的分页插件PageHelper-4.1.1的使用
    svn设置提交忽略某些文件或文件夹
    HTML编辑器 图片粘贴上传,实现图文粘贴,图片自动上传
    java 支持 超大上G,多附件上传方案
  • 原文地址:https://www.cnblogs.com/xiaonanxia/p/4843995.html
Copyright © 2011-2022 走看看