函数指针,指向成员函数的指针与指向成员变量的指针

本文探讨了函数指针的概念及应用,包括普通函数指针、指向成员函数的指针和指向虚拟成员函数的指针。详细介绍了如何声明、初始化和使用这些指针,并讨论了它们之间的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.从函数指针说起

   可以声明一个指向特定函数的指针:

       void (*fp)(int); //指向函数的指针(函数指针)

   注意:其中的括号是必不可少的,它表明fp是一个指向返回值为void的函数的指针,而不是返回值为void*的函数。

      void* fp(int);  //声明一个返回值为void*的函数(指针函数)

  

   函数指针的赋值:指向函数的指针可以为空,否则它就应该指向一个具有适当类型的函数。(与特定的函数的声明完全一样)

 

    void (*fp)(int);

    int  f(int);

    void g(long);

    void h(int);

 

    /////

    fp = f; //错误;&f 的类型为int (*)(int)

    fp = g;//错误;&g的类型为void (*)(long)

    fp = 0;//正确,设为NULL

    fp = h;//正确,指向h

    fp = &h;//正确,明确赋予函数地址

 

注意:将一个函数的地址初始化或赋值给一个指向函数的指针时,无需显式的取得函数地址,编译器知道隐式的获得函数的地址,因此在这种情况下&操作符是可有可无的,通常省略不用。类似的,为了调用函数指针所指向的函数而对指针进行解引用操作也是不必要的,因为编译器可以帮你解引用。

    (*fp)(12); //显式的解引用

    fp(12); //隐式的解引用,结果相同

 

一个函数指针指向内联函数(inline function)是合法的。然而,通过函数指针调用内敛函数将不会导致内联式的函数调用。因为编译器通常无法再编译期精确的确定将会调用什么函数。因此在调用点,编译器别无他法,只好生成间接的非内联的函数调用代码。(函数指针就是指向函数的地址,如果编译器在编译时把指向的函数识别为内联函数,那内联函数就会把函数体原地展开,而不存在所谓的函数调用了,那函数指针该指向哪呢,可以这么理解)

 

参考:http://book.51cto.com/art/201011/232490.htm

 

2.指向成员函数的指针和指向成员变量的指针

   

    这里成员函数可分为:非静态成员函数,静态成员函数和虚拟成员函数。

    成员变量可分为:非静态成员变量和静态成员变量。

 

    我们都知道,在C++程序被编译时,类的成员函数的实现被放置在代码段,与类的实例是分开存放的,成员函数供所有类的实例共享。然而,不同性质的函数被我们调用的方式是不同的。

 

    静态成员函数可以说和我们使用的一般的函数基本没有区别。只不过静态成员函数的作用域限定在类中。我们可以定义一个普通的函数指针,然后让它指向静态成员函数,接下来我们就可以对函数指针进行引用了。

 

    非静态成员函数和一般的函数有很大的区别。我们不能定义一个普通的函数指针,让它指向非静态的成员函数。

 

具体请看代码:

 

   

    运行结果为:

    &A::sum = 00401109

    &A::sub = 004010D7

    &A::a = 0047CDF0

    &A::b = 0047CDF4

    &A::c = 00000008

    &A::d = 0000000C

    object.sum = 00401109

    object.sub = 004010D7

    object.a = 0047CDF0

    object.b = 0047CDF4

    object.c = 0012FF78

    object.d = 0012FF7C

   

    5

    -1

    -1

 

    从上面的结果可知静态成员函数和非静态成员函数放在一起,都在代码区中。静态成员变量放在静态数据区中,所以在定义对象object之前,就可以获取a和b的地址,然而,我们使用&A::c和&A::d获取的是非静态成员变量在类的实例中的偏移,上面两个函数指针占8个字节,所以得到c和d的偏移为8和12。当我们定义对象后,我们使用object.c和object.d就可以获取c和d在内存中的实际地址。

 

   后面对函数指针的测试,可以看出静态成员函数与非静态成员函数的区别。

 

3. 指向虚拟成员函数的指针

    那么虚拟机制能够在使用“指向成员函数的指针”的情况下运行吗?答案是肯定的。对一个非静态成员函数取地址,将得到该函数在内存中的实际地址。然而,面对一个虚拟函数,其地址在编译时期是未知的,所能知道的仅是虚拟函数在其相关虚拟函数表(virtual table)中的索引值。也就是说,对一个虚拟成员函数(virtual member function)取其地址,所能获得只是一个索引值。

 

    但是虚拟机制的实施完全由编译器来控制。

   

 参考:《深入探索C++对象模型》

   

 

 

### 使用函数指针指向类的成员函数 在C++中,使用函数指针指向类的成员函数需要特别注意,因为成员函数普通函数不同,它隐含了一个`this`指针作为参数。因此,定义和使用类成员函数指针时需要遵循特定的规则。 #### 定义成员函数指针 为了定义一个指向成员函数指针,必须包含类的作用域,并且指针类型需要明确指定返回值和参数列表。以下是一个示例: ```cpp class Test { public: void func() { std::cout << "Member function called!" << std::endl; } }; void (Test::*funcPtr)() = &Test::func; // 定义指向成员函数指针 ``` 上述代码中,`funcPtr`被定义为指向`Test`类中的成员函数`func`的指针[^3]。 #### 调用成员函数指针 调用成员函数指针时,必须通过具体的对象实例进行操作,因为成员函数需要访问该对象的数据成员。以下是完整的调用示例: ```cpp #include <iostream> using namespace std; class Test { public: void func() { cout << "Member function called!" << endl; } }; int main() { Test t; // 创建对象实例 void (Test::*funcPtr)() = &Test::func; // 定义成员函数指针 // 使用对象调用成员函数指针 (t.*funcPtr)(); return 0; } ``` 在这个例子中,`(t.*funcPtr)()`表示通过对象`t`调用成员函数指针`funcPtr`所指向的函数[^1]。 #### 静态成员函数指针 静态成员函数普通函数类似,不需要通过对象调用,因此可以像普通函数指针一样定义和使用。例如: ```cpp class MathCalculation { public: static int add(int a, int b) { return a + b; } }; typedef int (*FuncCal)(int, int); int main() { FuncCal funAdd = &MathCalculation::add; // 定义静态成员函数指针 int ret1 = (*funAdd)(1, 2); // 调用方式普通函数相同 int ret2 = funAdd(3, 3); cout << "ret1 = " << ret1 << endl; cout << "ret2 = " << ret2 << endl; return 0; } ``` 这里,`funAdd`是一个普通的函数指针指向静态成员函数`add`[^4]。 #### 注意事项 - 对于非静态成员函数,必须通过对象实例调用。 - 成员函数指针的定义需要明确类的作用域以及函数的返回值和参数列表。 - 静态成员函数指针可以像普通函数指针一样使用,因为它不依赖于具体对象。 ### 示例总结 以上代码展示了如何定义和使用指向成员函数指针,包括非静态成员函数和静态成员函数的情况。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值