C++之this指针与另一种“多态”
一、引入
定义一个类的对象,首先系统已经给这个对象分配了空间,然后会调用构造函数(说明:假设存在构造函数--2010.9.5修正)。
一个类有多个对象,当程序中调用对象的某个函数时,有可能要访问到这个对象的成员变量。
而对于同一个类的每一个对象,都是共享同一份类函数。对象有单独的变量,但是没有单独的函数,所以当调用函数时,系统必须让函数知道这是哪个对象的操作,从而确定成员变量是哪个对象的。
这种用于对成员变量归属对像进行区分的东西,就叫做this指针。事实上它就是对象的地址,这一点从反汇编出来的代码可以看到。
二、分析
1、测试代码:
/////////////////////////////////////////////////////////////////////////////////////#include<iostream>using namespace std;/////////////////////////////////////////////////////class A{public: A(char *szname) { cout<<"construct"<<endl; namenew char[20]; strcpy(name, } ~A() { cout<<"destruct"<<endl; delete name; } void show();private: char *name;};/////////////////////////////////////////////////////void A::show(){ cout<<"name<<name<<endl;}/////////////////////////////////////////////////////int main(){ A"zhangsan"); a.show(); system("pause"); return 0;} |
程序在VC++6.0 32位操作系统上编译、运行。
对编译后的EXE文件,进行反汇编。反汇编工具为OllyDbg。
2、反汇编分析
关键点截图如下:
(1)从图1可以发现this指针通过ECX寄存器,传递给了成员函数。this指针就是对象的地址。

图 1 Main函数
(2)从图 2可以发现访问对象的成员变量用的就是之前通过ECX传入的this指针。

图 2 show()函数
三、深入理解
通过截图及相关的资料,可以很清晰的知道在调用构造函数、show()函数之前的那个ECX就是this指针,也就是说这是一个验证性的实验,答案已经很清楚了,所要做的就是去动手体验一下。但是,假如我不懂C++、我不懂什么this指针,我一样可以发现这个叫做“this指针”的东西。通过OD的动态调试,当显示出了name时,逐步回溯可以发现name的源头是ECX。OD重新载入,查看在进入show()函数之前ECX是哪里来的,最终可以一步步的发现,ECX就是一个地址,这个地址里边的第一个值也是一个地址,指向一串字符串。再往上分析,进入show()上边的构造函数,可以发现里边有new操作,strcpy操作,这里就发现了字符串空间、内容的来源。至此,基本就分析完了。
通过这个过程可以发现很多C++的知识。如:对象的空间是在调用构造函数之前就分配好了的;对象里边没有函数;this指针通过寄存器ECX传递;通过声明定义的对象它的空间分配在栈中;等等这些跟系统或者C++有关联的知识。
但是,对于一个不懂C++的人看来,上面一段的体会都是没有的。从汇编指令看不出C++的思想,this指针不过是一个地址;对象不过是一些空间;构造函数、析构函数以及其它的函数,也不过是一堆指令的集合。
C++的同一个类定义出来的多个对象,从汇编指令看来是这样的:有很多块地址空间,它们有相同的大小。当不同的对象调用成员函数时,在汇编指令看来是:它们都call同一个地址,这个call指令其实里边是一个jmp指令,用于跳向某个位置,在call指令之前一般都会把一个地址放到ECX中,当然有时候会用堆栈或者其它寄存器。
C++的继承、多态、封装,对汇编程序员来说是看不出有什么神奇的,对于C++程序员来说那可就不同了,可以省去很多的工作,把很多事情都交给了编译器,让编译器自动给你搞定。
C++程序员所讨论的对象及其众多的特点、优点,最终还是变成了“低级”的指令,而且可能是效率低下的指令,即便如此,它的优点仍远大于缺点,它让编程变得容易、高效。
四、延伸
忽然想到了C++的多态,一句话“将子类类型的指针赋值给父类类型的指针”,多态是通过虚函数实现。对虚函数及其相关内容的原理、详细理解就不细说了。
说下我的简单理解,有一个基类A和子类B、C,有一个函数以基类A的指针为参数,然后在函数里头通过指针调用基类的成员函数。假如这个被调用的基类成员函数不是虚函数,那么是不可能实现多态的,因为翻译成汇编指令的时候,调用成员函数的这个地方是一个call指令,然后这个call指令跳到某个地方去执行,这是一个固定了的地址。通过定义为虚函数,调用成员函数的这个地方是通过虚函数表指针来确定调用哪个函数的,而虚函数表指针就放在对象的地址空间中,如果对象变了,那么虚函数表指针也变了,调用的函数也就不同了。对于那个以基类A的指针为参数的函数,指针即是对象的地址,如果传递的地址是子类B或者C的对象的地址,那么虚函数表指针也就不同了,调用的成员函数也就不同了。
这就是多态,这种多态使得调用同一个函数,因为传递参数的不同而显示出差异,参数可以是基类对象或者众多不同的子类对象。它们的差异是类与类之间的。
有虚函数的对象的内存布局,比没有虚函数的对象多了一个指向虚函数表的指针。因为虚函数的调用是通过虚函数表指针来实现的,所以有了多态。
再考虑一下C++的this指针,一个类中的成员函数,依据this指针来区分不同的对象,也就是说根据this指针实现了访问不同的对象的成员变量。
这是否也是多态的一种表现?这里所说的多态已经不是那个“父类指针指向子类对象”的教条了,而是体现在同一个类的不同对象之间,调用同一个成员函数,依据参数“this指针”来实现访问不同的对象的成员变量。成员函数访问成员变量,在编译期无法确定它访问的成员变量在哪一个地址的,只有到了运行期依据this指针才能确定访问的地址。这一点很类似于类的多态:以基类指针为参数的函数里调用了某个基类的虚成员函数,在编译期无法确定程序运行时调用的会是哪个类的对象,只有到了运行期才确定会调用哪个类的对象。
this指针识别了同一个类的不同的对象,换句话说,this指针使得成员函数可以访问同一个类的不同对象。再深入一点,this指针使得成员函数会因为this指针的不同而访问到了不同的成员变量。这也是多态吧,只是它是必然存在的多态,这种多态跟基类与派生类之间的多态是不同级别的多态,它不像一般的多态可以通过对使用虚函数的选择来取舍,它是一个类对应多个对象、多个对象共享一份成员函数代码带来的必然结果。
原文地址:http://www.cnblogs.com/cswuyg/archive/2010/08/21/1805153.html
C++之this指针与另一种“多态”的更多相关文章
- Qt 智能指针学习(7种指针)
Qt 智能指针学习 转载自:http://blog.csdn.net/dbzhang800/article/details/6403285 从内存泄露开始? 很简单的入门程序,应该比较熟悉吧 ^_^ ...
- Qt 智能指针学习(7种QT的特有指针)
从内存泄露开始? 很简单的入门程序,应该比较熟悉吧 ^_^ #include <QApplication> #include <QLabel> int main(int arg ...
- Qt 智能指针学习(7种QT智能指针和4种std智能指针)
从内存泄露开始? 很简单的入门程序,应该比较熟悉吧 ^_^ #include <QApplication> #include <QLabel> int main(int arg ...
- c,const和指针组合的几种意义
const和指针的组合: 注释部分表示非法. ; ; p=&a; //*p = 1 ; ; pp= &a; //*pp = 1; ; //pv=&a; *pv = ; ; // ...
- 改变javascript函数内部this指针指向的三种方法
在查了大量的资料后,我总结了下面的三条规则,这三条规则,已经可以解决目前我所遇到的所有问题.规则0:函数本身是一个特殊类型,大多数时候,可以认为是一个变量. function a() { alert( ...
- C++:C++的两种多态形式
// // main.cpp // Test.cpp // // Created by mac on 15/8/11. // Copyright (c) 2015年. All rights reser ...
- C++基础 (8) 第八天 数组指针 模板指针 C语言中的多态 模板函数
1昨日回顾 2 多态的练习-圆的图形 3多态的练习-程序员薪资 4员工管理案例-抽象类和技术员工的实现 employee.h: employee.cpp: technician.h: technici ...
- C++中为什么要用虚函数、指针或引用才能实现多态?
原文链接:http://blog.csdn.net/zoopang/article/details/14071779 学过C++的都知道,要实现C++的多态性必须要用到虚函数,并且还要使用引用或者指针 ...
- 为什么C++中只有指针和引用才能实现多态?
代码: class A { public: virtual void Debug(){} }; class B:public A { public: virtual void Debug(){} }; ...
随机推荐
- 关于函数的return
function add(x, y) { var total = x + y; return total; } add(5,10); 关于函数的return 我一开始是认为没有什么用的 后来在项目中 ...
- 【很强大的Android图表引擎 - AChartSDK】
在手机移动App开发中,图表在app中越来越占领举足轻重的地图.而在Android领域.AchartEngine 图表引擎可谓无人不知无人不晓. 可是今天就给各位推荐更为强大的图表引擎. 为什么说更为 ...
- 【BZOJ3743】[Coci2015]Kamp 树形DP
[BZOJ3743][Coci2015]Kamp Description 一颗树n个点,n-1条边,经过每条边都要花费一定的时间,任意两个点都是联通的. 有K个人(分布在K个不同的点)要集中到一个点举 ...
- 【BZOJ2460】[BeiJing2011]元素 贪心+高斯消元求线性基
[BZOJ2460][BeiJing2011]元素 Description 相传,在远古时期,位于西方大陆的 Magic Land 上,人们已经掌握了用魔法矿石炼制法杖的技术.那时人们就认识到,一个法 ...
- 怎样过滤跨站恶意脚本攻击(XSS)
什么是XSS? XSS(Cross Site Scripting),即跨站脚本攻击,是一种常见于web application中的计算机安全漏洞.XSS通过在用户端注入恶意的可运行脚本,若服务器端对用 ...
- YY大厅接受不到documentcompleted事件处理
多玩大厅在接受到了页面的documentcompleted事件,才会把遮在页面前面的YY游戏中去掉,我们的游戏页面,YY大厅接收不到事件,所以就排查了下 发现原因在于js脚本里有个用iframe做上报 ...
- 我的Android进阶之旅------>如何将Android源码导入Eclipse中来查看(非常实用)
Android源码下载完成的目录结构如如所示: step1:将.classpath文件拷贝到源代码的根目录 Android源码支持多种IDE,如果是针对APP层做开发的话,建议大家使用Eclipse开 ...
- python初学者总结
学习python首先配置好工作环境,因为不同版本之间的python是不兼容了 原创:01coding.com win7安装环境过程: 1:下载python 建议下载两个不同版本官方已给出 https: ...
- Tensorflow官方文档中文版——第二章(瞎奖杯写)
包含如下几个部分: 1.面向机器学习初学者的 MNIST 初级教程 2.面向机器学习专家的 MNIST 高级教程 3.TensorFlow 使用指南 4.卷积神经网络 5.单词的向量表示(word e ...
- ggplot2绘图系统
ggplot2包实现了一个在R中基于全面一致的语法创建图形时的系统 .在ggplot2中,图是采用串联起来(+)号函数创建的.详细内容参见<ggplot2:数据分析与图形艺术>,这里只简要 ...