主题:[讨论]类成员函数地址的问题
broook
[专家分:0] 发布于 2010-06-01 07:53:00
#include <iostream>
using namespace std;
class Object
{
public:
void f(){
cout << "Object::f()";
}
void f(int){
cout << "Object::f(int)";
}
};
int main()
{
cout << "Object::f :"<< &Object::f<<endl;
}
这个代码编译会出错,那么该如何获得 Object::f()和Object::f(int)的地址呢?
回复列表 (共3个回复)
沙发
alweeq86 [专家分:1170] 发布于 2010-06-01 08:52:00
[code=c]
#include <iostream>
using namespace std;
class Object
{
public:
void f(){
cout << "Object::f()";
}
void f(int){
cout << "Object::f(int)";
}
};
int main()
{
void (Object::*p)();//用两个指向成员函数的指针
void (Object::*q)(int);
q=&Object::f;
p=&Object::f;
cout << "Object::f :"<< p<<endl;
cout << "Object::f(int):"<<q<<endl;//断点设在这一行
}
[/code]
执行到断点后 监视器中:
名称 值 类型
Object::f(void) 0x00161600 Object::f(void) void (void)
Object::f(int) 0x00161650 Object::f(int) void (int)
*p 0x00161262 Object::f(void) void (void)
*q 0x00161271 Object::f(int) void (int)
p 0x00161262 Object::f(void) void (void)*
q 0x00161271 Object::f(int) void (int)*
看了半天我也挺糊涂的 请高手解答
板凳
eastcowboy [专家分:25370] 发布于 2010-06-02 00:38:00
“指向非static的成员函数的指针”(为了方便起见,下面简称“成员函数指针”),这个话题有点复杂。
“成员函数指针”虽然也属于指针,但它跟一般的指针差距可不小。
首先,C语言的所有类型的指针(甚至包括指向函数的指针),都可以隐式转化为void指针。但是“成员函数指针”则不能这样转化,否则编译器报错。
其次,32位系统中,一般指针的大小都是4字节,但成员函数指针则不一定。可能有朋友不太相信,让我们眼见为实:[quote]class T1
{
};
class T2A
{
};
class T2B
{
};
class T2 : public T2A, public T2B
{
};
class T3A
{
};
class T3 : virtual public T3A
{
};
class T4;
#include <stdio.h>
int main()
{
printf("%d\n", sizeof(void(T1::*)()));
printf("%d\n", sizeof(void(T2::*)()));
printf("%d\n", sizeof(void(T3::*)()));
printf("%d\n", sizeof(void(T4::*)()));
return 0;
}[/quote]
运行环境Visual C++ Express 2008,采用默认的编译选项,输出结果为4, 8, 12, 16。
实验发现,在VC系列的编译器中,采用默认的编译选项,一个类在不继承(或者单继承)、多继承、virtual继承、未定义这四种情况下,其“成员函数指针”的大小分别是4, 8, 12, 16字节。
根据网上其他人的测试数据,有的编译器在有的情况下,“成员函数指针”甚至可以占用20个字节。
就楼主的问题,希望取得成员函数的地址,并输出。这个要求看起来很简单,但我也没有什么好的解决办法。如何输出一个占用16个字节的值呢?除了采用一些不可移植的手段,我真的想不出其它办法来。
即使可以确保所有的“成员函数指针”都是4个字节,也没有什么好的办法可以顺利的输出正确的函数地址。对于一般的成员函数,确实可以用这4个字节保存函数代码所在的内存地址,但是对于virtual成员函数,则并不是这样——virtual函数需要根据对象的实际类型确定最终应该调用哪个函数,此时对象都还没有指定,怎么可能得到正确的函数地址呢?
我把1楼alweeq86的代码稍作修改,得到如下代码:
[quote]#include <iostream>
using namespace std;
class A
{
};
class B
{
};
class Object
{
public:
virtual void f(){
cout << "Object::f()";
}
void f(int){
cout << "Object::f(int)";
}
};
int main()
{
void (Object::*p)();//用两个指向成员函数的指针
void (Object::*q)(int);
p = &Object::f;
q = &Object::f;
printf("%p\n", p);
printf("%p\n", q);
Object o;
o.f();
o.f(10);
}[/quote]
运行时输出
012D1267
012D1226
查看汇编代码为:
o.f();
0011157A lea ecx,[o]
0011157D call Object::f (1110F5h)
o.f(10);
00111582 push 0Ah
00111584 lea ecx,[o]
00111587 call Object::f (111226h)
可见,非virtual的那个函数(带int的版本)的地址是正确的,都是0x00111226。而virtual的那个函数地址是错误的,输出的是0x012D1267,但实际上却是0x001110F5。
3 楼
alweeq86 [专家分:1170] 发布于 2010-06-02 07:48:00
高手 向你致敬!
[b]一个类在不继承(或者单继承)、多继承、virtual继承、未定义这四种情况下,其“成员函数指针”的大小分别是4, 8, 12, 16字节。[/b]
这个还真不知道,有空我试一下。
我来回复