类中的静态成员函数,和非类中的普通函数,函数名即为函数地址:
#include<iostream>
using namespace std;
class A{
public:
void fun1(){}
static void fun2(){}
};
void fun3(){}
int main(){
cout << &A::fun1 << '\t' << A::fun2 << '\t' << fun3 << endl;
}
输出为:1 010D1226 010D1249
可以看到后面两个是函数地址,而fun1却是1,而且fun1需要取地址符号&,否则编译不通过:
'A::fun1': function call missing argument list; use '&A::fun1' to create a pointer to member,编译器不认为A::fun1是一个函数(地址),我单步调试到<ostream>中查看源码,但是f11进去1就已经输出了,这个1是怎么输出出来的,有待研究,知道的人望留言告知。
试了一下用
printf("%p\n", &A::fun1);
能输出地址。这里不纠结了。
既然能直接输出地址,那么就能用普通的函数指针操作类中的成员函数:
#include<iostream>
#include<sstream>
using namespace std;
int trans(string str){
stringstream os;
os << str;
os.flags(os.hex);
int temp;
os >> temp;
return temp;
}
class A{
public:
void fun1(){ cout << "fun1 call" << endl; }
static void fun2(){}
};
void fun3(){}
typedef void(*P)();
int main(){
char buf[9];
sprintf(buf,"%p", &A::fun1);
P pr = (P)trans(string(buf, buf + 8));
pr();
}
另外附上完整的测试代码(包含用类对象来调用普通成员函数的地址):
#include<iostream>
#include<sstream>
using namespace std;
int trans(string str){
stringstream os;
os << str;
os.flags(os.hex);
int temp;
os >> temp;
return temp;
}
class A{
public:
void fun(){
cout << "A::fun call" << endl;
}
static void fun2(){
cout << "fun2(static) call" << endl;
}
};
void fun1(){
cout << "fun1 call" << endl;
}
typedef void( A::*p_void_class)();//__thiscall
typedef void(*P_void_normal)();//normal
int main(){
A a;
p_void_class p = &A::fun;
char temp[9];
sprintf(temp,"%p", p);
cout << (void*)trans(string(temp, temp + 8)) << endl;
P_void_normal adrr = (P_void_normal)trans(string(temp, temp + 8));//将p转化为普通指针
cout << adrr << endl;
printf("%p\n", p);//调用printf能输出 __thiscall 函数指针
P_void_normal p1 = fun1;
P_void_normal p2 = A::fun2;
adrr();//调用fun
(a.*p)();//调用fun,用对象来调用
p1();//调用fun1
p2();//调用fun2
return 0;
}
后来我看到一个“奇怪”的现象,new一个对象的指针,将其delete后,该指针任然能访问其成员函数
A* p = new A;
delete p;
p->fun1();
这是为何?想了一下想明白了,就算执行p=NULL或者delete p;p的类型不会改变,仅仅是把对象的数据成员占据的内存释放了。既然是A*的类型,当然能访问A里面的成员函数,就像下面这样
//int x=rand();
char x='a';
((A*)x)->fun1();
不管x是什么东西,字符也好,随机整数也好,只要是能转化成指针类型的都能访问fun1();
这也充分说明类中普通成员函数(有虚函数时只是多了个虚表)和类对象是分离的。所有的类对象访问的是同样的成员函数,和类外的普通函数没什么区别。一个类对象的指针访问成员函数时,该指针的值已经没有任何意义,编译器能直接根据类型找到函数的入口地址。至于如何得到类中成员函数的入口地址,前面已经讲过方法,不再赘述。