阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

C++ 函数指针 及类成员函数指针概述

77次阅读
没有评论

共计 2825 个字符,预计需要花费 8 分钟才能阅读完成。

导读 函数指针是指函数存放在内存的代码区域内,它们同样有地址. 如果我们有一个 int test(int a) 的函数,那么,它的地址就是函数的名字,这一点如同数组一样,数组的名字就是数组的起始地址。

C++ 函数指针 及类成员函数指针概述

函数指针

函数存放在内存的代码区域内,它们同样有地址. 如果我们有一个 int test(int a) 的函数,那么,它的地址就是函数的名字,这一点如同数组一样,数组的名字就是数组的起始地址。

函数指针的定义方式
data_types (*func_pointer)(data_types arg1, data_types arg2, ...,data_types argn);

例如:

int test(int a) { return a; } int main(int argc, const char * argv[]) { int (*fp)(int a); fp = test; cout<<fp(2)<<endl; return 0; }

注意 :函数指针所指向的函数一定要保持函数的返回值类型,函数参数个数,类型一致。

typedef 定义可以简化函数指针的定义

实例

int test(int a) { return a; } int main(int argc, const char * argv[]) { typedef int (*fp)(int a); fp f = test; cout<<f(2)<<endl; return 0; }
函数指针同样是可以作为参数传递给函数的

实例

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 f = test; cout<<test2(f, 1)<<endl; // 调用 test2 的时候,把 test 函数的地址作为参数传递给了 test2 return 0; }

执行以上代码,输出结果为:

10
利用函数指针,我们可以构成函数指针数组,更明确点的说法是构成指向函数的指针数组。

实例

void t1(){cout<<"test1"<<endl;} void t2(){cout<<"test2"<<endl;} void t3(){cout<<"test3"<<endl;} int main(int argc, const char * argv[]) { typedef void (*fp)(void); fp b[] = {t1,t2,t3}; // b[] 为一个指向函数的指针数组 b[0](); // 利用指向函数的指针数组进行下标操作就可以进行函数的间接调用了 return 0; }
指向类成员函数的函数指针

定义:类成员函数指针(member function pointer),是 C++ 语言的一类指针数据类型,用于存储一个指定类具有给定的形参列表与返回值类型的成员函数的访问信息。

基本上要注意的有两点:

  1. 函数指针赋值要使用 &
  2. 使用 .* (实例对象) 或者 ->*(实例对象指针)调用类成员函数指针所指向的函数

下面看两个例子:

A) 类成员函数指针指向类中的非静态成员函数
对于 nonstatic member function(非静态成员函数)取地址,获得该函数在内存中的实际地址

对于 virtual function(虚函数), 其地址在编译时期是未知的,所以对于 virtual member function(虚成员函数)取其地址,所能获得的只是一个索引值

实例

// 指向类成员函数的函数指针
#include 
#include 
using namespace std;
 
class A
{
    public:
        A(int aa = 0):a(aa){}
 
        ~A(){}
 
        void setA(int aa = 1)
        {a = aa;}
        
        virtual void print()
        {cout *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

B) 类成员函数指针指向类中的静态成员函数
实例

#include 
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++ 的多重继承、虚继承而带来的类实例地址的调整问题,所以类成员函数指针在调用的时候一定要传入类实例对象。

阿里云 2 核 2G 服务器 3M 带宽 61 元 1 年,有高配

腾讯云新客低至 82 元 / 年,老客户 99 元 / 年

代金券:在阿里云专用满减优惠券

正文完
星哥玩云-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2024-07-25发表,共计2825字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中