今天突然想起了类成员函数指针,于是想到几个问题:
1. 一个类的成员函数指针可以转化为另一个类的成员函数指针么?
2. 类成员函数指针与普通函数指针真的完全不一样么?
接下来的讨论将回答这两个问题! (有关类成员函数指针概念请参考相关资料....)
一,类虚成员函数指针的内部实现:
class CTest
{
public:
};
void main()
{
}
程序运行后输出call ShowMsg In CTest Class...
分析汇编源代码,发现给my_virtual_fun_ptr赋值的汇编代码为:
mov
这里多出来一个莫名其妙的符号:??_9CTest@@$BA@AE。继续查找,发现原来它是一个函数(应该是编译器自动产生的一个辅助函数):
;
_TEXT
??_9CTest@@$BA@AE PROC
??_9CTest@@$BA@AE ENDP
可以看到,它实现的功能仅仅是从ECX得到this指针,然后跳转到类的虚函数表中对应的函数入口处!而且通过这种方式,调用同一个类的不同虚成员函数,编译器会为各个不同虚成员函数的调用,各自产生一个类似的函数。例如:如果类有多个虚函数,我们通过成员函数指针去调用第二个虚函数,那么产生的类似函数第二条指令为:jmp
通过以上的分析,虚成员函数的调用方式是编译器产生一个中间函数来管理this指针的传递!!所以只要this指针传递正确,那么调用就可以正确实现。这里没涉及到不同的类的情况,所以我猜测第一个问题的答案是,可以进行转化,于是写了下面的代码:
class CTest
{
public:
};
class CTestAnother
{
public:
};
void main()
{
}
程序运行后的输出:call ShowMsg In CTestAnother Class...haha...
哈哈,转化成功,而且还是把无参的成员函数指针,转化成了有参的成员函数指针。
so....对于虚成员函数指针的情况,因为它的内部实现只是正确传递this指针,所以不管类之间是继承还是毫无关系,都可以进行指针转化。
对于非虚成员函数,由于它的内部特性,不能进行类之间的成员函数指针转化。原因请看后面的分析!
二,非虚成员函数指针的内部实现:
class CTest
{
public:
};
void main()
{
}
程序的输出为:call ShowMsg In CTest Class...
对于程序的输出毫无疑问,看看对my_fun_ptr赋值的汇编代码:
mov
发现编译器是直接使用的CTest类的ShowMsg函数地址....也就是不涉及到类的信息,这种特性和普通的函数完全一样(这里指的普通函数指非类的成员函数)
既然特性和普通函数没有区别,那是不是代表我可以把类的成员函数,强制转化为一个普通函数来使用呢?答案是肯定的,哈哈.....
class CTest
{
public:
private:
};
void main()
{
}
程序的输出为:call ShowMsg In CTest Class...10
哈哈....成功把类的成员函数指针,转化为普通函数指针来调用了!!
这里要说明一下的是,我试过各种办法,无法直接把my_fun_ptr强制转化为NFT_fun_ptr类型。所以只有借助嵌入汇编!不过后来想到另一种方法也可以实现这种转化:
union
哈哈,这里利用了union共享内存的特性,然后直接访问addr成员,就完成了所需要的转化!!
这种方法很不错哦,可以推广到许多无法通过普通手段进行类型转化的情况!
所以对于第二个问题的回答是:两者没什么区别!!
总结一下:
虚成员函数指针,可以在不同类之间进行任意转化,而非虚成员函数指针,由于实现的方式与普通函数一样,所以无法进行不同类之间的转化!!非虚成员函数指针,可以转化为普通函数指针,而且实现方式与普通函数指针完全一样(唯一不一样的是this指针的传递)