C++学习–函数指针和类成员函数指针「建议收藏」

C++学习–函数指针和类成员函数指针「建议收藏」就是指向函数的指针,它与普通指针类型一样,所占内存为4字节(32位系统)

C++学习--函数指针和类成员函数指针「建议收藏」"

函数指针

函数指针就是指向函数的指针,它与普通指针类型一样,所占内存为4字节(32位系统)。不同的是,它存储的是函数的地址而非数据地址。

//有两个参数,分别是char*和int且返回值是int的函数指针
int (*pFunc)(char*, int);
//无参数且返回类型是整型的函数指针
int (*somefunction)();
//有两个整型参数且返回值是bool的函数指针

把一个函数赋给一个函数指针

int foo()
{
    return 5;
}
 
int goo()
{
    return 6;
}
 
int main()
{
    int (*funcPtr)() = foo; // funcPtr 现在指向了函数foo
    funcPtr = goo; // funcPtr 现在又指向了函数goo
    return 0;
}

funcPtr = goo()//;这是把goo的返回值赋值给了funcPtr

类成员函数指针

顾名思义就是类中的成员函数的函数指针

要注意两点:
1.函数指针复制要使用&
2.使用 .* (实例对象)或者 ->*(实例对象指针)调用类成员函数指针所指向的函数

一.类成员函数指针指向类中的非静态成员函数

对于非静态成员函数取地址,获得该函数在内存中的实际地址

对于虚函数, 其地址在编译时期是未知的,所以对于虚成员函数取其地址,所能获得的只是一个索引值,这个索引值是该虚函数在虚函数表的偏移位置

对于指向非静态的类成员函数的函数指针,引用时必须传入一个类对象的this指针,所以必须由类实体调用。

当类成员函数声明为静态的,函数与类的任何特定对象相对独立。静态成员函数即使在类对象不存在的情况下也能被调用,静态函数只要使用类名加范围解析运算符 :: 就可以访问,不需要通过类实例对象调用。

静态成员函数只能访问静态成员数据、其他静态成员函数和类外部的其他函数。

//指向类成员函数的函数指针
#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;
};
 
class B:public A
{
    public:
        B():A(), b(0){}
        
        B(int aa, int bb):A(aa), b(bb){}
 
        ~B(){}
 
        virtual void print()
        {
            A::print();
            cout << "B: " << b << endl;
        }
 
        virtual void printa()
        {
            A::printa();
            cout << "B: " << b << endl;
        }
    private:
        int b;
};
 
int main(void)
{
    A a;
    B b;
    void (A::*ptr)(int) = &A::setA;
    A* pa = &a;
    
    //对于非虚函数,返回其在内存的真实地址
    printf("A::set(): %p\n", &A::setA);
    //对于虚函数, 返回其在虚函数表的偏移位置
    printf("B::print(): %p\n", &A::print);
    printf("B::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;
}

代码执行结果为:

A::set(): 0x8048a38
B::print(): 0x1
B::print(): 0x5
A: 0
A: 10
A: 100
A: 1000
A: 10000

二.类成员函数指针指向类的静态成员函数
 

#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成员函数赋值
         **
         **再有,赋值时如果直接&memberVariable,则在VS中报"编译器错误 C2276"
         **参见:http://msdn.microsoft.com/zh-cn/library/850cstw1.aspx
         */
        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
    
    //使用.*(实例对象)或者->*(实例对象指针)调用类成员函数指针所指向的函数
    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;
}

类成员函数指针与普通函数指针不是一码事。前者要用 .* 与 ->* 运算符来使用,而后者可以用 * 运算符(称为”解引用”dereference,或称”间址”indirection)。

普通函数指针实际上保存的是函数体的开始地址,因此也称”代码指针”,以区别于 C/C++ 最常用的数据指针。

而类成员函数指针就不仅仅是类成员函数的内存起始地址,还需要能解决因为 C++ 的多重继承、虚继承而带来的类实例地址的调整问题,所以类成员函数指针在调用的时候一定要传入类实例对象。

今天的文章C++学习–函数指针和类成员函数指针「建议收藏」分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/79907.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注