zoukankan      html  css  js  c++  java
  • C++类的成员函数的指针和mem_fun适配器的用法

    一、普通函数指针

    我们先来看一个最简单的函数:

    void fool(int a)
    {
        cout << a<< endl;
    }

    那么它的函数指针类型为:

    void (*) (int)

    我们可以这样测试:

    void (*pFunc)(int) = &foo;//这里pFunc是个指针
    pFunc(123);

    这样就会打印出整数123;
    为了简化,我们可以使用typedef:

    typedef void (*pFunc)(int);

    这里我们要说明一下:

    这里的pFunc是 返回值为空,一个形参为int型的函数类型 的一个别称;即pFucn为一个类型,我们可以把pFunc类比为int,double

    那么我们就可以这样用:

    #include<iostream>
    #include <string>
    using namespace std;
    
    void fool(int a)
    {
        cout << a<< endl;
    }
    
    int main(int argc, const char *argv[])
    {
        typedef void (*pFunc)(int);
        
        pFunc fc = &fool;//fc就相当于一个变量(函数指针)
    
        fc(1223);
        return 0;
    }

    以上就是函数指针的基本应用。

    二、类的成员函数

    那么,对于类的成员函数,我们该怎么声明以及应用呢?

    观察下面的类:

    class Foo
    {
        public:
            void foo(int a)
            { cout << a << endl; }
            
            static void bar(int a)
            { cout << a << endl; } 
    };

    我们在main函数中这样调用:

    void (*pFunc)(int) = &Foo::foo;

    会发现,编译器会报出这样一条错误:

    error: cannot convert ‘void (Foo::*)(int)’ to ‘void (*)(int)’ in initialization

    从上面的编译错误,我们得知,foo的函数指针类型不是我们期望的 void (*)(int),foo的函数指针类型其实是void (Foo::*)(int)型。
    原因很简单:类的成员函数,含有一个隐式参数this,以foo为例,这里foo实际存在两个参数,一个便是this指针,另一个才是int型变量。

    我们尝试使用 void (Foo::*)(int)类型,代码如下:

    void (Foo::*pFunc2) (int) = &Foo::foo;

    我们该如何使用呢?有以下两种方式:

     Foo f; //对象通过   .  方式调用
    (f.*pFunc2)(12345);
    Foo *pf = &f ;//对象指针通过 -> 方式调用
    (pf->*pFunc2)(123124);


    这里我们还注意到,上述类中含有一个static成员函数,它有什么特点呢?

    void (*pFunc)(int) = &Foo::bar;//ok
    pFunc(123);

    我们在main函数调用以上代码,发现能成功运行。这是由于static成员的特性决定的:

    static将本函数声明为本类所有,而不是单个类的对象。因此我们可以想使用普通函数那样使用static成员函数。

    完整代码如下:

    #include <iostream>
    #include <string>
    #include <typeinfo>
    using namespace std;
    
    class Foo
    {
        public:
            void foo(int a)
            { cout << a << endl; }
            
            static void bar(int a)
            { cout << a << endl; } 
    };
    
    int main(int argc, const char *argv[])
    {
    //veersion 1      
        //void (*pFunc)(int) = &Foo::foo;//error 
        //Foo::foo 的形式参数有两个:一个隐式,一个int
        //void (*pFunc)(int)的形式参数只有一个
        // pFunc(123);
    
    //version 2    
        void (*pFunc)(int) = &Foo::bar;//ok
        pFunc(123);
        //这里表明:static成员函数的参数没有隐式参数(本对象)
    
    //修正1-->为其加一个参数即可    
        void (Foo::*pFunc2)(int) = &Foo::foo;
        Foo f;
        (f.*pFunc2)(12345);
        Foo *pf = &f ;
        (pf->*pFunc2)(123124);
        return 0;
    }


    三、mem_fun适配器:

    头文件:<functional>

    既然foo含有一个隐式参数,那么能否将其转化出来呢?我们使用STL中俄mem_fun,这是一种函数适配器。

    Foo f;
    //void (Foo::*)(int)->void (*)(Foo*,int)
    (mem_fun(&Foo::foo))(&f,123);

    mem_fun的具体作用是一种转化作用,将void (Foo::*)(int)类型的成员函数指针转化为void (Foo*, int),后者是一个自由函数类型的指针,可以像static成员函数那样自由调用。

  • 相关阅读:
    POC- Proof of Cocept -- 概念验证
    英语语法学习 7 -- 数词
    英语语法学习6 -- 代词
    英语语法学习5-冠词
    英语语法学习4-名词
    英语语法学习3-句子的组成和分类
    alibaba-Java开发手册心得-一编程规约-4oop(面向对象编程)规约
    alibaba-Java开发手册心得-一编程规约-3代码格式
    alibaba-Java开发手册心得-一编程规约-2常量定义
    魔法值的简单了解
  • 原文地址:https://www.cnblogs.com/xfxu/p/4017773.html
Copyright © 2011-2022 走看看