//
理论上而言调用一个类的成员函数只需要知道类实例的地址和类成员函数的地址和类成员函数参数类型等,而不需要知道类的类型,但除了使用汇编之外却别无它法
#include
#include
using namespace std;
//
参数分别是 类实例地址, 类成员函数地址, 类成员函数参数
// 之所以使用...作参数,因为了去掉一些类型转换
__declspec(naked)
bool print( ... )
{
__asm {
//
压入了3个字节长度的变量,以后的esp要加上12
push ebx
push esi
push
edi
mov eax, dword ptr [(esp+12)+4] // 将对象地址保存到EAX
mov
ebx, dword ptr [(esp+12)+8] // 将类成员地址保存到EBX
mov ecx, dword ptr
[(esp+12)+0] // 此函数的返回地址
mov cl, byte ptr [ecx+2] //
__cdecl返回地址处是个add ebp,?语句,取得?,即参数长度
movzx ecx, cl //
将cl扩展到ecx中
sub ecx, 8 //
对象地址4字节长+成员函数地址4字节长
sub esp, ecx
// memcpy( esp,
esp+ecx+12, ecx )
shr ecx, 2 // ecx /=
4
lea esi, dword ptr [(esp+12)+ecx*4+12]
lea edi, dword
ptr [esp]
rep movsd
mov ecx, eax //
将类对象地址传入ecx,这是thiscall调用约定
call ebx // call
成员函数
pop edi
pop esi
pop
ebx
ret
}
}
// 以下为测试代码
struct
cls1
{
int i;
cls1():i(1234){}
virtual bool memfun(
const char* str )
{
cout << i << ' ' << str
<< endl;
return true;
}
};
struct cls2 :
cls1
{
int j;
cls2():j(4321){}
virtual bool memfun(
const char* str )
{
cout << i << ' ' << j
<< ' ' << str << endl;
return
false;
}
};
int main()
{
cls1 a;
cls2
b;
bool f1 = print( &a, cls1::memfun, "base" );
cout <<
f1 << endl;
bool f2 = print( &b, cls1::memfun, "derive" ); //
这里没有使用cls2::memfun,可以体现多态
cout << f2 <<
endl;
system( "Pause" );
return 0;
}
阅读(1669) | 评论(7) | 转发(0) |