C++成员不通过对象调用(.或->方式)的另类(C式)调用写法

#include <iostream>
using namespace std; /*
我们知道,成员函数和普通函数最大的区别就是成员函数包含一个隐藏的参数this指针,用来表明成员函
数当前作用在那一个对象实例上。 根据调用约定(Calling Convention)的不同,成员函数实现this指针的方式也不同。 1. 如果使用__thiscall调用约定,那么this指针保存在寄存器ECX中,VC编译器缺省情况下就是这样的。
2. 如果是__stdcall或__cdecl调用约定,this指针将通过栈进行传递,且this指针是最后一个被压入栈
的参数,相当于编译器在函数的参数列表中最左边增加了一个this参数。
*/
class Base {
public:
virtual void f() { cout << "Base::f()" << endl; }
virtual void g() { cout << "Base::g()" << endl; }
virtual void h() { cout << "Base::h()" << endl; } virtual void foo(Base *pThis) {
pThis->hello(this);
}
virtual void hello(Base *pThis) {
pThis->h();
} //virtual void __stdcall hello(Base *pThis) {} //成员函数指定了__stdcall调用约定
}; int test()
{
typedef void(*Fun)(); Base *b = new Base;
cout << *(int*)(&b) << endl; //虚函数表的地址存放在对象最开始的位置 Fun funf = (Fun)(*(int*)*(int*)b);
Fun fung = (Fun)(*((int*)*(int*)b + ));
Fun funh = (Fun)(*((int*)*(int*)b + )); /************************************************************************/
/* 调用内部无this参与的成员(包括变量和方法)的对象方法 */
/************************************************************************/ //如果下面三个方法里,没有用到与对象相关的成员可以不用为ecx赋值,否则会出错
funf();
fung();
funh(); /************************************************************************/
/* 调用内部有this参与的成员(包括变量和方法)的对象方法 */
/************************************************************************/ //少了__stdcall(注意位置),栈会不平衡了:本来c++默认是thiscall,如果不要,vs编译器会让调用者平衡栈,即多了一句 add esp, 4
typedef void(__stdcall *Fun_Base)(Base*);
Fun_Base foo = Fun_Base(*((int*)*(int*)b + )); //就是多增加这句,因为编译器对c++默认采用thiscall
_asm{
mov ecx, dword ptr[b]
} foo(b);//里面用到this了,不给ecx赋值,this就不对 /************************************************************************/
/* 调用内部有this参与的成员(包括变量和方法)的对象方法,纯汇编版本 */
/************************************************************************/ //尝试调用虚函数表的第四个方法
_asm{
//同上,如果所call的方法里,没有用到与对象相关的成员可以不用为ecx赋值,否则会出错
mov ecx, dword ptr[b] push ecx //一个入参 //mov ecx, b或mov eax, [b],表达同一个意思,vs最后都是mov ecx, dword ptr[b];
//实质是mov eax, [EBP-04h],结果表现为ecx=b,即从栈上获取指针b的值,而不是*b(即*(int*)b == ptr_vftable)的值。
mov eax, [b] //获取对象指针
mov eax, [eax] //虚函数表首地址,即对象的开始处,ptr_vftable = [eax + 0] = [ecx] = [this_of_b] = [b]
call [eax + 0x0c] //调用虚函数表的第四个,某虚函数表里第N个方法(x86),[ptr_vftable + (N - 1) * 4] = [[eax]+(N-1)*4]
} /************************************************************************/
/* 正常的调用 */
/************************************************************************/ /*
00EF9886 8B 45 F4 mov eax, dword ptr[b]
00EF9889 50 push eax
00EF988A 8B 4D F4 mov ecx, dword ptr[b]
00EF988D 8B 11 mov edx, dword ptr[ecx]
00EF988F 8B 4D F4 mov ecx, dword ptr[b]
00EF9892 8B 42 0C mov eax, dword ptr[edx + 0Ch]
00EF9895 FF D0 call eax
*/
b->foo(b); //http://blog.csdn.net/haoel/article/details/1948051/
/*
虚函数表的结束结点,就像字符串的结束符“/0”一样,其标志了虚函数表的结束。
这个结束标志的值在不同的编译器下是不同的。 1. 在WinXP+VS2003下,这个值是NULL。
2. 而在Ubuntu 7.10 + Linux 2.6.22 + GCC 4.1.3下,
2.1 这个值是如果1,表示还有下一个虚函数表,
2.2 如果值是0,表示是最后一个虚函数表。
*/
cout << (Fun)(*((int*)*(int*)b + )); // 最后一个位置为0,表明虚函数表的结束 return ;
}

C++虚函数介绍

1. 先从C++看看下虚函数表和多态表现 http://blog.csdn.net/haoel/article/details/1948051/

2. 有虚函数的类的大小 http://blog.csdn.net/hackbuteer1/article/details/7883531

3. 再从汇编看,类的继承,虚函数表的形成,表放在哪个地址等 http://www.pediy.com/kssd/pediy10/60538.html

虚函数表的形成,是在类构造函数里,对实例对象首地址里存放的虚函数数组进行修改实现的。

class Child :public Base{
public:
virtual void vf1(){cout<<"I'm in sub Class.";}
virtual void vf2(){cout<<"I'm in sub Class.";}
//...
}
.text                     .rdata?
class Child内存 这个类的所有对象所共有的
+-------------+ +-----+-----+-----+-----+----+
| ptr_vftable | -------> | vf1 | vf2 | vf3 | ... |end?|
+-------------+ +-----+-----+-----+-----+----+
| |
|other members|
| |
+-------------+

逆向C++(中文版)
http://wenku.baidu.com/link?url=bjLVj2eqfe29_Edzi99MBGJeoCtVaHDXj-3r4s4lm771BAQnJ0WIUaQywPZgGq3Yz_uU9yh-B0V6q5SFMUhRo0t436BUnUdaHuhpwERvLvC

C++多态性:

GoF著作中未提到的设计模式(4):Double Dispatch
http://www.cnblogs.com/west-link/archive/2011/07/26/2116887.html
http://en.wikipedia.org/wiki/Double_dispatch

C++成员不通过对象调用的直接调用写法的更多相关文章

  1. Java学习笔记11---静态成员变量、静态代码块、成员变量及构造方法的初始化或调用顺序

    当创建一个对象时,各种成员变量及构造方法的初始化或调用顺序是怎样的呢? (1).如果类尚未加载,则先初始化静态成员变量和静态代码块,再初始化成员变量,最后调用相应的构造方法: (2).如果类已经加载过 ...

  2. 12.C++-构造函数与析构函数调用顺序,const成员函数,const对象

    单个对象创建时,构造函数的调用顺序 1.首先判断该对象的类是否拥有父类,若有则先调用父类的构造函数 2.判断该对象的成员是否是其它类的成员,若是则调用成员变量的构造函数(调用顺序和声明顺序相同) 3. ...

  3. Java中 对象的创建于调用

    Main方法是程序的主入口,想要用某个方法必须在main方法中调用 创建对象: 类名 对象名 = new 类名(); 使用对象访问类中的成员: 对象名.成员变量: 对象名.成员方法(); 成员变量的默 ...

  4. PHP将在对象被销毁前调用这个函数.它称为析构函数

    -构造函数和析构函数 如果你在一个类中声明一个函数,命名为__construct,这个函数将被当成是一个构造函数并在建立一个对象实例时被执行.清楚地说,__是两个下划线.就像其它任何函数一样,构造函数 ...

  5. C#之转换两个不同类型但是成员相同的对象

    /// <summary> /// 转换两个不同类型但是成员相同的对象 /// </summary> /// <typeparam name="T"& ...

  6. 错误笔记 对象为null时调用改对象的方法会报错

    对象为null时调用改对象的方法会报错

  7. 【C++】私有数据成员不能用对象去访问吗

    首先,必须清楚的是private和public限定的是类而不是对象.因此,在成员函数中访问同类对象的私有成员是完全可以的. 所以,某些教材上所说的“私有数据成员不能用对象去访问”是欠妥当的. 比如,如 ...

  8. 反射-优化及程序集等(用委托的方式调用需要反射调用的方法(或者属性、字段),而不去使用Invoke方法)

    反射-优化及程序集等(用委托的方式调用需要反射调用的方法(或者属性.字段),而不去使用Invoke方法)   创建Delegate (1).Delegate.CreateDelegate(Type, ...

  9. 《oracle每天一练》触发器不能调用或间接调用COMMIT,ROLLBACK等DCL语句

    触发器不能调用或间接调用COMMIT,ROLLBACK等DCL语句 在触发器中不能运行 ddl语句和commit,rollback语句 ddl语句:DDL语句用语定义和管理数据库中的对象,如Creat ...

随机推荐

  1. 洛谷 [P3620] 数据备份

    贪心神题 首先我们发现一个显然的贪心策略,连接相邻两个写字楼总是更优. 所以本题就变成了数轴上一堆点,要选 k 个彼此不相邻的区间,使得区间长度最小 对于 10000 的数据来说,我们可以用 DP 解 ...

  2. 洛谷 P1038 神经网络

    题目背景 人工神经网络(Artificial Neural Network)是一种新兴的具有自我学习能力的计算系统,在模式识别.函数逼近及贷款风险评估等诸多领域有广泛的应用.对神经网络的研究一直是当今 ...

  3. 只有mdf文件而没有ldf文件修复方法

    原文发布时间为:2010-09-16 -- 来源于本人的百度文章 [由搬家工具导入] 只有mdf文件而没有ldf文件修复log文件或者重新生成一个log文件的方法 EXEC   sp_attach_s ...

  4. 回发或回调参数无效 “HtmlSelect”不能有类型为“LiteralControl”的子级

    原文发布时间为:2009-11-14 -- 来源于本人的百度文章 [由搬家工具导入] 回发或回调参数无效 “HtmlSelect”不能有类型为“LiteralControl”的子级 出现这两个错误,一 ...

  5. form+iframe+file 页面无刷新上传文件并获取返回值

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  6. Vim查找替换及正则表达式的使用

    原文地址:http://tanqisen.github.io/blog/2013/01/13/vim-search-replace-regex/ 简单替换表达式 :[range]s/from/to/[ ...

  7. 浅谈控件(组件)制作方法一(附带一delphi导出数据到Excel的组件实例)(原创)

    来自:http://blog.csdn.net/zhdwjie/article/details/1490741 -------------------------------------------- ...

  8. flashcache 介绍

    rpm: flashcache-utils-0.0-4.1.el6.x86_64 kmod-flashcache-0.0-3.el6.x86_64 基本介绍: Flashcache是Facebook技 ...

  9. hdu 4517(递推枚举统计)

    小小明系列故事——游戏的烦恼 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)To ...

  10. iOS地图多个自定义大头针绘制核心代码

    首先需要自定义一个包含经纬度,title,subtitle的数据模型 #import <Foundation/Foundation.h> #import <MapKit/MapKit ...