C++对象布局及多态实现之成员函数的调用

从这部分开始我们除了利用内存的信息打印来进行探索外,更多的会通过跟踪和观察编译器产生的汇编代码来理解编译器对这些语言特性的实现方式。汇编方面知识的讨论超出了本文的范围,我只对和我们讨论相关的汇编代码进行解析。理解本文要讨论的知识并不需要有很完整的汇编知识,但必须了解起码的概念。

下面我们看看引入虚继承后的影响。为了有所对比我们首先看看普通成员函数的调用情况。

执行如下代码,它包括了对象的普通成员函数调用,类的静态成员函数调用、通过指针调用普通成员函数:

C010 obj;
PRINT_OBJ_ADR(obj)
obj.foo();
C012::sfoo();
C010 * pt = &obj;
pt->foo();


结果如下:

obj's address is : 0012F843

这是obj对象的内存地址。

首先我们看看对象的普通成员函数调用,obj.foo();,对应的汇编代码为:

00422E09 lea ecx,[ebp+FFFFF967h]

00422E0F call 0041E289

第1行把对象的地址存入ecx寄存器,执行完这行指令后,我们要以看到ecx中的值为0x0012F843,就是前面打印出的值。如果函数需要传递参数,我们还会在前面看到一些push指令。在第2行我们可以看到call的是一个直接的地址,这也就是静态绑定。即函数的调用地址在编译时已经被编译器决议。

跟踪进去我们要以看到是一条跳转指令,继续执行可以看到真正的函数代码部分,如下(注:为了讨论方便我在第行前面加了一个行号):

01 00425FE0 push ebp
02 00425FE1 mov ebp,esp
03 00425FE3 sub esp,0CCh
04 00425FE9 push ebx
05 00425FEA push esi
06 00425FEB push edi
07 00425FEC push ecx
08 00425FED lea edi,[ebp+FFFFFF34h]
09 00425FF3 mov ecx,33h
10 00425FF8 mov eax,0CCCCCCCCh
11 00425FFD rep stos dword ptr [edi]
12 00425FFF pop ecx
13 00426000 mov dword ptr [ebp-8],ecx
14 00426003 mov eax,dword ptr [ebp-8]
15 00426006 mov byte ptr [eax],2
16 00426009 pop edi
17 0042600A pop esi
18 0042600B pop ebx
19 0042600C mov esp,ebp
20 0042600E pop ebp
21 0042600F ret


我们看看第7行,把ecx寄存器入栈,后面4行初始化了函数的堆栈中的保存局部变量的部分。第12行弹出ecx值,到这里时ecx的值保持为在函数调用前存入的对象内存地址,第13行就是保存this指针的值,作为一个局部变量。这样我们就知道了VC7.1不是象传递普通函数那样通过压栈来传递this 指针,而是通过ecx寄存器来传递。第14、15行利用这个this指针给对象的成员变量进行了赋值。

再看看静态成员函数调用的汇编代码:

00422E14 call 0041DD84

非常直接,因为它不需要处理this指针,跟踪到函数的汇编代码,可以看到同样不需要处理this指针。具体的代码这里就不列出来了。

再看看通过指针调用普通成员函数pt->foo();,产生的汇编代码如下:

00422E25 mov ecx,dword ptr [ebp+FFFFF958h]

00422E2B call 0041E289

和通过对象调用普通成员函数的代码差不多。不过存对象地址到ecx寄存器地,是通过解引用pt指针来找到对象地址的。

时间: 2024-08-01 12:31:56

C++对象布局及多态实现之成员函数的调用的相关文章

C++对象布局及多态之虚成员函数调用

在构造函数中调用虚成员函数,虽然这是个不很常用的技术,但研究一下可以加深对虚函数机制及对象构造过程的理解.这个问题也和一般直观上的认识有所差异.先看看下面的两个类定义. struct C180 { C180() { foo(); this->foo(); } virtual foo() { cout << "<< C180.foo this: " << this << " vtadr: " << *(

C++对象布局及多态实现探索之虚函数调用

我们再看看虚成员函数的调用.类C041中含有虚成员函数,它的定义如下: struct C041{C041() : c_(0x01) {}virtual void foo() { c_ = 0x02; }char c_;}; 执行如下代码: C041 obj;PRINT_DETAIL(C041, obj)PRINT_VTABLE_ITEM(obj, 0, 0)obj.foo();C041 * pt = &obj;pt->foo(); 结果如下: The detail of C041 is 14

浅析成员函数和常成员函数的调用_C 语言

在Coordinate类中,有一个Display()成员函数和一个Display() const常成员函数,代码如下 class Coordinate{ public: Coordinate(int x,int y); void Display() const; void Display(); private: int m_iX; int m_iY; }; #include <iostream> #include "Coordinate.h" using namespace

static成员函数不能调用non-static成员函数

1 一般类静态成员函数不能调用非静态成员函数 2 static成员函数可以调用构造函数吗? 答案是肯定的,由于static成员函数没有this指针,所以一般static成员函数是不能访问non-static成员的,包括成员函数和成员变量. 由于构造函数特殊性,它从无到有构造一个对象,因此调用它不需要一个instance,也就是不需要this指针来调用,所以在static 函数中能调用构造函数.o 构造函数分成两个阶段:    1. 分配内存:这是从无到有阶段,该阶段结束,产生一个instance

C++对象布局及多态探索之菱形结构虚继承

这次我们看看菱形结构的虚继承.虚继承的引入本就是为了解决复杂结构的继承体系问题.上一篇我们在讨论虚继承时用的是一个简单的继承结构,只是为了打个铺垫. 我们先看看这几个类,这是一个典型的菱形继承结构.C100和C101通过虚继承共享同一个父类C041.C110则从C100和C101多重继承而来. struct C041{ C041() : c_(0x01) {} virtual void foo() { c_ = 0x02; } char c_;};struct C100 : public vir

C++对象布局及多态实现探索之虚继承

下面我们来看虚继承.首先看看这C020类,它从C010虚继承:} struct C010{ C010() : c_(0x01) {} void foo() { c_ = 0x02; } char c_;};struct C020 : public virtual C010{ C020() : c_(0x02) {} char c_;}; 运行如下代码,查看对象的内存布局: PRINT_SIZE_DETAIL(C020) 结果为: The size of C020 is 6The detail o

C++对象布局及多态实现的探索(二)

虚函数的类的对象布局(1) 如果类中存在虚函数时,情况会怎样呢?我们知道当一个类中有虚函数时,编译器会为该类产生一个虚函数表,并在它的每一个对象中插入一个指向该虚函数表的指针,通常这个指针是插在对象的起始位置.所谓的虚函数表实际就是一个指针数组,其中的指针指向真正的函数起始地址.我们来验证一下,定义一个无成员变量的类C040,内含一个虚函数. struct C040 { virtual void foo() {} }; 运行如下代码打印它的大小及对象中的内容. PRINT_SIZE_DETAIL

C++对象布局及多态实现探索之内存布局

为了便于分析和观察对象的内存布局,我把代码生成时的结构成员对齐选项设置为1字节,默认为8字节.如果你在自己的工程下编译文中的代码,请做同样的设置.因为我写了一些函数打印对象中的布局信息,如果对象选项不是1字节,运行这些代码会出现指针异常错误. 普通类对象的内存布局 首先我们从普通类对象的内存布局开始.c000为一个空类,定义如下: struct c000 {}; 运行如下代码打印它的大小及对象中的内容. print_size_detail(c000) 结果为: the size of c000

C++对象布局及多态实现的探索

前言 本文通过观察对象的内存布局,跟踪函数调用的汇编代码.分析了C++对象内存的布局情况,虚函数的执行方式,以及虚继承,等等. 写这篇文章源于我在论坛上看到的一个贴子.有人问VC使用了哪种方式来实现虚继承.当时我写了一点代码想验证一下,结果发现情况比我想象的要复杂.所以我就干脆认真把相关的问题都过了一遍,并记录成本文. 我对于C++对象模型的知识主要来自于Lippman的书<Inside the C++ Object Model>,中译版为候捷翻的<深度探索C++对象模型>,中英版