类成员函数指针的特殊之处(成员函数指针不是指针,内含一个结构体,需要存储更多的信息才能知道自己是否virtual函数)

下面讨论的都是类的非静态成员函数。

类成员函数指针的声明及调用:

1
2
3
4
5
6
7
//pr是指向Base类里的非静态成员函数的指针
//其行参为(int, int),返回值为void
void (Base::*pr)(int, int);
 
//需通过对象调用
//object是Base类的一个对象或指针(可多态)
( object->*pr)( _r, _c)

而其实质和普通的指针也有区别:

//下面是隐藏的代码是相关类型的定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void Foo1(int a, int b, int c)
{
    return;
}
 
void Foo2(int a, int b)
{
    return;
}
 
class Base{
public:
    void Foo3(int a, int b, int c)
        {return;}
    void Foo3(int a,int b)
        {return;}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include<iostream>
using namespace std;
 
int main()
{
    void (Base::*p1)(int,int,int) = &(Base::Foo3);
    void (Base::*p2)(int,int) = &(Base::Foo3);
    void (Base::*p3)(int,int,int) = NULL;
    cout<<"Foo1: "<<Foo1<<' '<<sizeof(&Foo1)<<' '
        <<"Foo2: "<<Foo2<<' '<<sizeof(&Foo2)<<' '
        <<"p1:   "<<p1<<' '<<sizeof(p1) <<' '
        <<"p2:   "<<p2<<' '<<sizeof(p2) <<' '
        <<"p3:   "<<p2<<' '<<sizeof(p3) <<endl;
}

输出结果为:

Foo1: 00BB1510  4 
Foo2: 00BB1520  4 
p1:   1 4 
p2:   1 4 
p3:   0 4

从结果上来看,指向成员函数的指针值均为1。且在调试过程中可以看到:

p1    error: cannot obtain value    void*

p2    error: cannot obtain value    void*

p3    error: cannot obtain value    void*

但这个指针指向的函数实际上是可以被调用的。

搜索之,看到了一篇文章:

http://blog.csdn.net/hairetz/archive/2009/05/06/4153252.aspx

1。成员函数指针不是指针。从代码看出,在main函数的调用栈(calling stack)中首先依次压入四个成员函数指针,如果它们是普通指针的话,它们之间的偏移量应该是4个字节,可是实际的情况却是这样的:

”The implementation of the pointer to member function must store within itself information as to whether the member function to which it refers is virtual or nonvirtual, information about where to find the appropriate virtual function table pointer (see The Compiler Puts Stuff in Classes [11, 37]), an offset to be added to or subtracted from the function's this pointer (see Meaning of Pointer Comparison [28, 97]), and possibly other information. A pointer to member function is commonly implemented as a small structure that contains this information, although many other implementations are also in use. Dereferencing and calling a pointer to member function usually involves examining the stored information and conditionally executing the appropriate virtual or nonvirtual function calling sequence.“

这篇文章较深入地研究了成员函数指针,及比较了普通成员函数指针和虚函数指针在转化的过程中存在那些差异。

原文地址:https://www.cnblogs.com/findumars/p/6328391.html