【转】C++ this指针(直戳本质)
转自:http://c.biancheng.net/view/170.html
为了能让大家看清 this 指针的本质,我们会先讲一点 C++ 的历史——C++ 程序到C程序的翻译过程。
C++ 程序到C程序的翻译
C++ 是在C语言的基础上发展而来的,第一个 C++ 的编译器实际上是将 C++ 程序翻译成C语言程序,然后再用C语言编译器进行编译。
C语言没有类的概念,只有结构,函数都是全局函数,没有成员函数。翻译时,将 class 翻译成 struct、对象翻译成结构变量是显而易见的,但是对类的成员函数应该如何翻译?对myCar.Modify();
这样通过一个对象调用成员函数的语句,又该如何翻译呢?
C语言中只有全局函数,因此成员函数只能被翻译成全局函数;myCar.Modify();
这样的语句也只能被翻译成普通的调用全局函数的语句。那如何让翻译后的 Modify 全局函数还能作用在 myCar 这个结构变量上呢?答案就是引入“this 指针”。下面来看一段 C++ 程序到C 程序的翻译。
C++程序:
- class CCar
- {
- public:
- int price;
- void SetPrice(int p);
- };
- void CCar::SetPrice(int p)
- {
- price= p;
- }
- int main()
- {
- CCar car;
- car.SetPrice(20000);
- return 0;
- }
class CCar
{
public:int price;void SetPrice(int p);
};void CCar::SetPrice(int p)
{price= p;
}
int main()
{CCar car;car.SetPrice(20000);return 0;
}
翻译后的C程序(此程序应保存为扩展名为 .c 的文件后再编译):
- struct CCar
- {
- int price;
- };
- void SetPrice(struct CCar* this, int p)
- {
- this->price = p;
- }
- int main()
- {
- struct CCar car;
- SetPrice(&car, 20000);
- return 0;
- }
struct CCar
{int price;
};
void SetPrice(struct CCar* this, int p)
{this->price = p;
}
int main()
{struct CCar car;SetPrice(&car, 20000);return 0;
}
可以看出,类被翻译成结构体,对象被翻译成结构变量,成员函数被翻译成全局函数。但是C程序的全局函数 SetPrice 比 C++ 的成员函数 SelPrice 多了一个参数,就是struct CCar *this
。car.SetPrice(20000);
被翻译成SetPrice(&car, 20000);
,后者在执行时,this 形参指向的正是 car 这个变量,因而达到了 SetPrice 函数作用在 car 变量上的效果。
思考题:以上翻译还不完整,因为构造函数的作用没有体现出来。思考构造函数应该如何翻译。另外,静态成员函数和静态成员变量应如何翻译?
this 指针的作用
实际上,现在的C编译器从本质上来说也是按上面的方法来处理成员函数和对成员函数的调用的,即非静态成员函数实际上的形参个数比程序员写的多一个。多出来的参数就是所谓的“this指针”。这个“this指针”指向了成员函数作用的对象,在成员函数执行的过程中,正是通过“Ihis指针”才能找到对象所在的地址,因而也就能找到对象的所有非静态成员变量的地址。
下面程序的运行结果能够证明这一点:
- #include <iostream>
- using namespace std;
- class A
- {
- int i;
- public:
- void Hello(){ cout << "hello" << endl; }
- };
- int main()
- {
- A* p = NULL;
- p -> Hello();
- }
#include <iostream>
using namespace std;
class A
{int i;
public:void Hello(){ cout << "hello" << endl; }
};
int main()
{A* p = NULL;p -> Hello();
}
sing namespace std;
class A
{int i;
public:void Hello(){ cout << "hello" << endl; }
};
int main()
{A* p = NULL;p -> Hello();
}
程序的输出结果是:
hello
在上面的程序中,p 明明是一个空指针,为何通过它还能正确调用 A 的成员函数 Hello 呢?因为,参考上面 C++ 到C程序的翻译,P->Hello()
实质上应该是Hello(p)
,在翻译后的 Hello 函数中,cout 语句没有用到 this 指针,因此依然可以输出结果。如果 Hello 函数中有对成员变量的访问,则程序就会出错。
C++ 规定,在非静态成员函数内部可以直接使用 this 关键字,this 就代表指向该函数所作用的对象的指针。看下面的例子:
- #include <iostream>
- using namespace std;
- class Complex {
- public:
- double real, imag;
- Complex(double r, double i) : real(r), imag(i) {}
- Complex AddOne()
- {
- this->real++;
- return *this;
- }
- };
- int main()
- {
- Complex cl(1, 1), c2(0, 0);
- c2 = cl.AddOne();
- cout << c2.real << "," << c2.imag << endl; //输出 2,1
- return 0;
- }
#include <iostream>
using namespace std;
class Complex {
public:double real, imag;Complex(double r, double i) : real(r), imag(i) {}Complex AddOne(){this->real++;return *this;}
};
int main()
{Complex cl(1, 1), c2(0, 0);c2 = cl.AddOne();cout << c2.real << "," << c2.imag << endl; //输出 2,1return 0;
}
第 9 行,this 指针的类型是 Complex*。因为 this 指针就指向函数所作用的对象,所以 this->rear 和 real 是完全等价的。*this
代表函数所作用的对象,因此执行第 16 行,进入 AddOne 函数后,*this
实际上就是 c1。因此的 c2 值会变得和 c1 相同。
因为静态成员函数并不作用于某个对象,所以在其内部不能使用 this 指针;否则,这个 this 指针该指向哪个对象呢?
【转】C++ this指针(直戳本质)相关推荐
- matlab this指针,C++ this指针(直戳本质)
为了能让大家看清 this 指针的本质,我们会先讲一点 C++ 的历史--C++ 程序到C程序的翻译过程. C++ 程序到C程序的翻译 C++ 是在C语言的基础上发展而来的,第一个 C++ 的编译器实 ...
- android系统戳,直戳ARM长处 首个RISC-V版Android 10系统顺畅运行
原标题:直戳ARM长处 首个RISC-V版Android 10系统顺畅运行 平头哥芯片开放社区本周四公布的一段视频显示,安卓10系统(代号Android 10系统)顺畅运行在平头哥玄铁910 RISC ...
- 轻码云大沙拉出位:用验证码直戳创客痛点
小码哥在激情四射的周末参加了大沙拉的超级创业大赞助商腾讯开放平台和一众合作方就为这次的活动奠定了高规格的基调.比如共筹网.科技寺.思微.活动行.梦创空间.轻码云...... 活动在一个周末52小时内让 ...
- 读书档案-深度思维:透过复杂直抵本质的跨越成长方法论
书名:<深度思维:透过复杂直抵本质的跨越成长方法论> 类别:学习/思维 作者:叶修 时间:2021年2月18日 1.阅读这本书的目标(为什么选择?为什么要购买?) 了解提升深度思维的常见方 ...
- Java高频面试题解析,直戳面试官痛点,多家互联网大厂Offer等你拿
前言 回顾多灾多难的2021年,新冠疫情持续肆虐全球,疫情确诊曲线起伏跌宕,由此引发一系列事件:经济萎缩. 财政刺激.疫苗研发.经济复苏等等.无不牵动着市场的神经."后疫情时代"将 ...
- 零基础逆向工程24_C++_01_类_this指针_继承本质_多层继承
1 类内的成员函数和普通函数的对比 1.1 主要是从参数传递.压栈顺序.堆栈平衡来总结. 1.参数传递:成员函数多传一个this指针 2.压栈顺序:成员函数会将this指针压栈,在函数调用取出 3.堆 ...
- C语言之数组和指针位移的本质(四十五)
#include <iostream> using namespace std;int main(){int stu[5] = {10,20,30,40,50};int *p1 = &am ...
- 直戳心窝的日常单品搭配指南,精致girl必看
前阵子和闺蜜逛街,这货突然问我怎样的穿搭才能赚足整条gai上的回头率,我说那就化个美美的妆,再来两件好看的衣服呗.还没等我说完,我的回答就被她diss了,她从化妆技术到衣服的颜色再到配饰的选择,狠狠的 ...
- 《Essential C++》学习笔记
目录 书籍介绍 此文由来 警告 第一章:C++编程基础 关于Vector 第二章:面向过程的编程风格 指针和引用的区别: 堆内存 inline函数 第三章:泛型编程风格 关于STL 顺序型容器 vec ...
最新文章
- 【Qt】重新认识QObject
- 威廉与玛丽学院读计算机博士,威廉与玛丽学院计算机科学(计算运算研究)理学硕士研究生申请要求及申请材料要求清单...
- Linux文件服务器实战(系统用户)
- 光纤模块与光纤收发器的区别
- QT 008 UI Add action 的方法
- crawlspider
- TCP 粘包和拆包及解决方案
- BCD码与十进制数间转换
- linux网卡驱动rtl8188cu,Realtek RTL8188CU芯片无线网卡的Linux驱动安装
- Axure RP 9.0 Enterprise 原型设计
- YOLOv3训练自己的数据详细步骤
- python爬房源信息_Python爬取链家二手房源信息
- Kaggle注册方法,解决人机验证问题
- 机器学习实践:非监督学习-8
- HTML表格自动排序
- 【C++ 科学计算】矩阵元素绝对值小于设定值时,元素值变为零
- c语言中声明子程序,哪位师傅知道51单片机怎样编写子程序?C语言的。在主程序里调...
- 记录一次Oracle自动化测试工具 - OATS实战分享
- 外泌体的三种分离方法及其临床意义
- SqlServer Management出现列名无效