zoukankan      html  css  js  c++  java
  • C++——将成员函数作为参数

    在C++中,成员函数指针作为参数传递给其他函数和普通函数指针的传递是不同的,首先 
    我们来回顾一下普通函数指针的传递方法: 
    //-------------------------------------------------------------------------- 
    int fun1(int i){ 
             return i; 

    void fun2(int j, int (*p)(int)){ 
             cout << p(j); 

    void main() 

             int i=1; 
             fun2(i,fun1); 

    //-------------------------------------------------------------------------- 
      
    只要在参数声明中声明是相同参数个数、类型和相同返回类型的函数指针int (*p)(int 
    ),传递时只需传函数名就可以了可是为什么在C++中,传递成员函数指针用此方法却不 
    能工作呢?我们先来回顾一下指针的概念,指针是指向一些内存地址的变量,既可以是 
    数据的地址也可以是函数的地址。C++的成员指针遵从同样的原则。困难的是所有的指针 
    需要一个地址,但在类内部没有地址;选择一个类的成员意味着在类中偏移。只有把这 
    个偏移和具体对象的开始地址结合,才能得到实际地址。成员指针的语法要求选择一个 
    对象的同时逆向引用成员指针。先来看看一个错误的例子: 
    //-------------------------------------------------------------------------- 
    class A 

    public: 
             int fun1(int i){return i;}; 
    }; 
    void fun2(int j, int (A::*p)(int)){ 
             cout <<p(j); 

    void main() 

             A oba; 
             int i=1; 
             fun2(i,oba.fun1);  //this is an error 

    //-------------------------------------------------------------------------- 
      
    当然,你可以把成员函数声明为static(静态函数),这样传递它的指针就像传递普通 
    函数一样,然而把成员函数定义成static类型无法真正解决问题,因为这样的话,该成 
    员函数就不能存取类中的非静态成员变量,而很多情况下既要求传递成员函数指针,又 
    要求该成员函数能够存取类中的非静态成员变量。 
    为了能够正确地传递成员函数指针,我们先来看看成员参数、成员函数指针正确的声明 
    方法: 
    //-------------------------------------------------------------------------- 
    class A 

    public: 
             int i1; 
             int fun1(int i){ 
                     return i; 
             }; 
    }; 
    void main() 

             int (A::*fp1)(int);    //声明fp1为class A中的成员函数指针 
             int A::*ip1;           //声明ip1为class A中的成员变量指针 
             fp1=&A::fun1;          //初始化fp1 
             ip1=&A::i1;            //初始化ip1 
             ip1=&A::i1;            //初始化ip1 
             A oba; 
             oba.*ip1=2; 
             (oba.*fp1)(oba.*ip1); 

    //-------------------------------------------------------------------------- 
      
    接下来就可以构造含有成员函数指针参数的函数了: 
    void fun2(int j, A ob, int (A::*p)(int)){ 
             cout <<(ob.*p)(j); 

    注意声明时必须加上一个对象参数A ob,因为只有把这个偏移和具体对象的开始地址结 
    合,才能得到实际地址。 
      
    另外,为了保证函数的健壮性和经济性,我们可以把对象参数改为对象指针参数: 
    void fun2(int j, A *obp, int (A::*p)(int)){ 
             cout <<(obp->*p)(j); 

      
    为了通用,我们还可以把这个函数声明为通用函数: 
    template <class T> 
    void fun2(int j, T *obp, int (A::*p)(int)){ 
             cout <<(obp->*p)(j); 

      
    这样就可以传递不同的类的成员函数指针给它了,以下为正确传递成员函数指针的例程: 
    //-------------------------------------------------------------------------- 
    class A 

    public: 
             int fun1(int i){ 
                     return i; 
             }; 
    }; 
    template <class T> 
    void fun2(int j, T *obp, int (T::*p)(int)){ 
             cout <<(obp->*p)(j); 

    void main() 

             int (A::*fp1)(int); 
             fp1=&A::fun1; 
             A oba; 
             A *obap=&oba; 
             int i=1; 
             fun2(i,obap,fp1); 

    //-------------------------------------------------------------------------- 
      
    但是这样声明之后就不能再传递普通函数指针给函数fun2了,为了更加通用,当然可以 
    显式地重载一下这个函数,以便它也能使用普通函数指针参数: 
    //-------------------------------------------------------------------------- 
    class A 

    public: 
             int fun1(int i){ 
                     return i; 
             }; 
    }; 
    template <class T> 
    void fun2(int j, T *obp, int (T::*p)(int)){ 
             cout <<(obp->*p)(j); 

    void fun2(int j, int (*p)(int)){ 
             cout << p(j); 

    int fun3(int i){ 
             return i; 

    void main() 

             int (A::*fp1)(int); 
             fp1=&A::fun1; 
             A oba; 
             A *obap=&oba; 
             int i=1; 
             fun2(i,obap,fp1); 
             fun2(i,fun3); 

    //--------------------------------------------------------------------------

  • 相关阅读:
    [Docker] redis 全配置
    Dubbo的负载均衡策略&容错策略
    Dubbo部分知识点总结
    如何win10 上访问虚拟机(linux)上redis方法
    Linux_centOS_5.7_64下如何安装jdk1.8&mysql
    java高级&资深&专家面试题-行走江湖必备-持续更新ing
    springCloud微服务调用失败【CannotGetJdbcConnectionException: Failed to obtain JDBC Connection】
    synchronized、volatile区别、synchronized锁粒度、模拟死锁场景、原子性与可见性
    ThreadLocal什么时候会出现OOM的情况?为什么?
    volatile、ThreadLocal的使用场景和原理
  • 原文地址:https://www.cnblogs.com/mupiaomiao/p/4904128.html
Copyright © 2011-2022 走看看