函数指针、类成员函数指针学习

发布时间 2024-01-06 16:42:15作者: lypbendlf

转自:https://www.runoob.com/w3cnote/cpp-func-pointer.html,写的非常好

1.函数指针

函数的函数名就是它的地址,存储在代码区。如同数组一样,数组的名字就是数组的起始地址。 

定义:

data_types (*func_pointer)( data_types arg1, data_types arg2, ...,data_types argn);
// 返回类型 (*函数指针名)(参数列表)
// * 是必须要有的
int (*fp)(int a); // 这里就定义了一个指向函数(这个函数参数仅仅为一个 int 类型,函数返回值是 int 类型)的指针 fp。

使用例子:

int test(int a) // 和fp定义相同的一个函数,返回类型和参数列表都相同
{
    return a;
}

int main(int argc, const char * argv[])
{
    
    int (*fp)(int a); // 声明一个函数指针
    fp = test;   // 可以用函数指针指向该函数
    cout<<fp(2)<<endl;  //  调用函数指针,=调用test函数

    // 通过typedef定义函数指针,在使用时直接使用该类型,更简洁 
    typedef int (*fp)(int a);
    fp f = test;
    cout<<f(2)<<endl;

    return 0;
}

 

1.1 函数指针做参数 

int test(int a)
{
    return a-1;
}
int test2(int (*fun)(int),int b)// 直接作为函数形参
{
    
    int c = fun(10)+b;// 直接调用
    return c;
}
 
int main(int argc, const char * argv[])
{
    
    typedef int (*fp)(int a); //定义一个函数指针类型fp
    fp f = test;
    cout<<test2(f, 1)<<endl; // 调用 test2 的时候,把test函数的地址作为参数传递给了 test2
    return 0;
}

 

2.类成员函数指针

  • 与普通函数的区别是,获取地址要加&符号;
  • 当调用类是实例时,用.*;类是对象指针时,用->*调用。

2.1 非静态成员函数 

//指向类成员函数的函数指针
#include <iostream>
#include <cstdio>
using namespace std;
 
class A
{
    public:
        A(int aa = 0):a(aa){}
 
        ~A(){}
 
        void setA(int aa = 1)
        {
            a = aa;
        }
        
        virtual void print()
        {
            cout << "A: " << a << endl;
        }
 
        virtual void printa()
        {
            cout << "A1: " << a << endl;
        }
    private:
        int a;
};
 
int main(void)
{
    A a;
    void (A::*ptr)(int) = &A::setA; // 定义一个指向A类的非static的成员函数setA指针ptr
    A* pa = &a; // 对象指针
    
    //对于非虚函数,返回其在内存的真实地址
    printf("A::set(): %p\n", &A::setA);
    //对于虚函数, 返回其在虚函数表的偏移位置
    printf("A::print(): %p\n", &A::print);
    printf("A::print(): %p\n", &A::printa);
 
    a.print();
 
    a.setA(10);
 
    a.print();
 
    a.setA(100);
 
    a.print();
    //对于指向类成员函数的函数指针,引用时必须传入一个类对象的this指针,所以必须由类实体调用
    (pa->*ptr)(1000); // 对象指针用->*
 
    a.print();
 
    (a.*ptr)(10000);// 实例调用用.*
 
    a.print();
    return 0;
}

//输出结果:
-> % ./Demo              
A::set(): 0x104d7ae7c
B::print(): 0x0
B::print(): 0x8
A: 0
A: 10
A: 100
A: 1000
A: 10000
View Code

 

2.2静态成员函数

#include <iostream>
using namespace std;
 
class A{
public:
    
    //p1是一个指向非static成员函数的函数指针
    void (A::*p1)(void);
    
    //p2是一个指向static成员函数的函数指针,区别是没有类名::
    void (*p2)(void);
    
    A(){
        /*对
         **指向非static成员函数的指针
         **和
         **指向static成员函数的指针
         **的变量的赋值方式是一样的,都是&ClassName::memberVariable形式
         **区别在于:
         **对p1只能用非static成员函数赋值
         **对p2只能用static成员函数赋值
         */
        p1 =&A::funa; //函数指针赋值一定要使用 &
        p2 =&A::funb;
        
        //p1 =&A::funb;//error
        //p2 =&A::funa;//error
        
        //p1=&funa;//error,编译器错误 C2276
        //p2=&funb;//error,编译器错误 C2276
    }
    
    void funa(void){
        puts("A");
    }
    
    static void funb(void){
        puts("B");
    }
};
 
int main()
{
    A a;
    //p是指向A中非static成员函数的函数指针
    void (A::*p)(void);
    
    (a.*a.p1)(); //打印 A ,这里调用好复杂,a.*是一个整体,a.p1表示对象a中定义的函数指针
    
    //使用.*(实例对象)或者->*(实例对象指针)调用类成员函数指针所指向的函数
    p = a.p1;
    (a.*p)();//打印 A
    
    A *b = &a;
    (b->*p)(); //打印 A
    
    /*尽管a.p2本身是个非static变量,但是a.p2是指向static函数的函数指针,
     **所以下面这就话是错的!
     */
//    p = a.p2;//error
    
    void (*pp)(void);
    pp = &A::funb;
    pp(); //打印 B
    
    return 0;
}
View Code

//真的好复杂,搞这么复杂,有什么应用场景吗,