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

来源:互联网 发布:nvidia怎么读 知乎 编辑:程序博客网 时间:2024/04/26 16:14

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++对象模型》

   

 

 

原创粉丝点击