c++中的this指针和c#中的this引用
先总结一下:
在c++中this为指针,使用"->"操作符来获取当前实例中的成员
在c#中this为引用,使用"."操作符来获取当前实例中的成员
下面内容转载自https://www.xzbu.com/8/view-8757098.htm,特别鸣谢。2019-01-0813:40:33
1 引言
this关键字在C++和C#程序中既随处可见,又无处不在:“随处可见”表明在程序中常常会看到它;“无处不在”说的是在每个类代码中都隐含有它。可以毫不夸张的说,没有理解“this”就没有完全理解类,因为你的类中或隐或现总会有若干个this。“this”到底是什么?它在程序中有什么作用?如何正确地使用它?搞清这些问题对于理解类的基本概念,提高面向对象程序设计的编程技巧大有裨益。
2 什么是this
常常会将“this”简单地理解为“这个”或“我自己”,大致相当于VB中的“Me”。这样理解过于笼统,应进一步明确为“我这个实例(或称当前实例)”,而不是“我这个类”或“我这个数据”等。
C++把this称为this指针,它代表了当前实例的内存地址,通过它可以访问当前实例的数据成员,通常写成“this->成员”或“*this. 成员”的形式。
C#把数据分为值类型和引用类型两大类,类实例属于引用类型,它在栈上存储实例的引用,在堆上存储实例的实际数据,因而把this称为this引用。访问当前实例的成员时,使用“.”操作符,在程序中应写成“this.成员”的形式。
3 c++中的this指针
C++用this指针来代表当前实例的内存地址,有了这个地址,就可以方便地访问到当前实例的所有成员。C++约定可以隐含或显式使用this。
3.1 隐含的this指针
学习过C而刚刚接触C++类概念的入门者会对myClass(int
m_x)函数中的“x=m_x;”感到十分奇怪:语句中的x是什么?依据面向过程的概念,一个函数中的任何变量都要有出处: 要么来自形参,要么是函数内部定义的局部变量,要么是全局变量。此处它们都不是,其实他们就是类的成员变量x。一个类可以创建多个实例,那x是哪个实例的数据呢?x又如 何能够穿透函数的屏蔽而在myClass()函数中变得可见呢?答案是:x是当前实例的数据,它们由this指针引导着,在类的成员函数中当然可见。
C++约定,在类的每个非静态成员函数的参数表中,都隐含有一个形参this,它是一个本类类型的指针变量,其作用是将当前实例的地址传送到函数内部,以便函数知道当前实例 的数据往哪里存取。如此,上例的myClass()函数未隐去参数this之前的本来面貌是:
myClass(myClass * this,int m_x)
{this->x=m_x; }
如此一来,这个函数理解起来就不存在任何问题了。
由于每个非静态成员函数都有这个参数this,为了简化编程,C++对这个参数作了隐含处理,这个函数就变成了
myClass(int m_x)
{this->x=m_x; }
至于函数内部的this->x中的this,可显式使用也可隐含,为了简便,一般都会隐去,于是便成了“x=m_x”。
了解以下结论至关重要:在类的每个非静态成员函数的参数表中,都隐含有一个形参this,它代表了当前实例的地址,在类的成员函数中使用当前实例的数据成员时,直接写出 它们的变量名就行了,其实此时它们前面都有一个隐含的this->。
知道了这一点,就可以理解类的运算符重载作为成员函数时,为什么可以省去一个形参(例如2个操作数只需1个形参),那是因为第一个参数就是this,而将其隐去了的缘故。
3.2 显式使用this指针
既然可以按约定省去this,C++程序员一般不会显式使用this指针。然而有时为了明确变量的归属,或者为了向成员函数内部传入当前实例的地址,或者需要强调使用当前实例, 必须显式使用this指针。
3.2.1 区分不同作用域的变量
下例C++程序中有三个作用域不同的x:全局变量x、类成员数据x和成员函数的局部变量x。
此时display()函数输出的是哪个x呢?C++规定,先匹配局部变量x,再匹配类的成员变量x,最后匹配全局变量x。因而输出结果应该是x=3。
若要输出当前实例的成员数据x,此时就必须显式指明this->x;若要输出全局变量x,需要用域操作符指明::x。为了验证起见,将display()函数改为如下形式(其余代码不变):
void myClass1::display()
{ int x=3;
coutxdisplay(this);//B类的display调用A类的display函数此处this是将B类当前实例的地址传入到A类的成员此例中关键的语句就是“p1->display(this);”,它是B类的成员函数display 的一句,作用是通过A类的指针p1去调用A类的成员函数display,但该函数需要B类实例地址作实参,那当然是它自己,即this。
3.2.3 用“*this” 代表当前对象
有时,类的成员函数或运算符需要强调当前对象,就必须用“*this”来表示。例如给上例中的A类增加一个前增运算符,它要求返回当前对象。
可以看出,以上三例中的this是无可替代的,此时必须显式使用this指针。
4 c#中的this引用
由于C#受管制代码不允许直接对地址进行操作,因而C#采用this引用来访问当前实例的数据。C#的this引用与C++
的this指针在用法上基本类似,对于隐含的约定也是相同的。 C#和C++毕竟是两种不同的语言,由于this引用对类成员的访问采用“.”操作符,其亲和力远胜于“->”
操作符,因而在C#程序中可看到更多的this。经常在程序中看到用this作函数 调用的实参,此时往往体现了编程者的匠心。
下一段C#程序演示了在一个类中去控制另一个类的属性:项目App1中有两个窗体,窗体1(Form1)中有一个命令按钮,单击它时显示窗体2(Form2)。窗体2中也有一个命令 按钮,单击它时将窗体1的背景色改为蓝色。为压缩篇幅,将程序中大部分由.NET
FrameWork自动生成的代码隐去(不会影响对程序的理解),留下来的代码中有阴影的部分是加 上去的。
Form2.GetForm1(this);//在Form1类中以this作实参调用Form2类的成员函数GetForm1, 就能将Form1类的当前实例传送到Form2类中去。}
// 这个函数在Form1中调用时是以this作实参(Form2.GetForm1(this))
// 因而fm1和Form1Ref都是Form1的当前实例的引用
程序说明了如何在一个类中去获取或操纵另一个类的信息的方法。因为C#不支持全局变量的使用,因而类之间信息的交换采用了将类的当前实例的引用传送到另一个类中的手段 来实现。这段程序具有普遍的意义。
c++中的this指针和c#中的this引用的更多相关文章
- f-stack中ipc传递指针从应用中读取信息时挂掉
f-stack中ipc传递指针从应用中读取信息时挂掉 如:创建bridge0./ifconfig bridge0 create./ifconfig f-stack-0 down./ifconfig f ...
- 利用C语言中的函数指针实现c++中的虚函数
C语言中的函数指针 #include<stdio.h> int fun1(int a) { return a*a; } int fun2(int a) { return a*a*a; } ...
- JS中的this指针
1.JS中this指针指向 JS中函数的 this 并不遵守词法作用域规则(即作用域由声明时所处的位置决定),而是取决于函数的调用方式 影响 this 指针的因素有以下: 方法是否由某个对象调用,比如 ...
- QT中使用函数指针
想仿命令行,所以定义了一个类,让一个String 对应一个 function,将两者输入list容器. 类中定义了 QString commandStr; void (MainWindow::*com ...
- Delphi中的函数指针判断是否为空
delphi函数指针 只有@@p才代表了函数指针本身的地址 assigned(p) 判断是否为空 或者用 @p=nil 来判断函数指针是不是为空 Delphi中的函数指针实际上就是指针,只是在使用 ...
- js中的this指针(三)
当一个函数并非一个对象的忏悔时,它会被当作一个函数来调用. 此时,函数中的 this 指针被绑定到了全局对象. 后果:方法不能利用内部函数来帮助工作,由于 this 被绑定了错误的值,将无法共享该方法 ...
- 由javascript中的this指针所想到的
初次结识 this 指针,是在学 <<C++ Primer Plus>>这本书的时候(这本书勉强读了一二遍,之后转学 html+css+js了,不过这是后话). 依稀记得书中举 ...
- c++中基类与派生类中隐含的this指针的分析
先不要看结果,看一下你是否真正了解了this指针? #include<iostream> using namespace std; class Parent{ public: int x; ...
- [BS-21] 关于OC中对象与指针的思考
关于OC中对象与指针的思考 1. 创建对象: OC中可通过代码Person *p = [[Person alloc] init];创建了一个对象p.该过程中内存情况为: 在当前线程的栈(默认1M)中, ...
随机推荐
- WITH RECOMPILE和OPTION(RECOMPILE)区别仅仅是存储过程级重编译和SQL语句级重编译吗
在考虑重编译T-SQL(或者存储过程)的时候,有两种方式可以实现强制重编译(前提是忽略导致重编译的其他因素的情况下,比如重建索引,更新统计信息等等), 一是基于WITH RECOMPILE的存储过程级 ...
- Mac键盘按键符号
通过修饰键来查看 像command.option.control.shift这些按键在Mac下叫做修饰键,一般情况下他们大都用来辅助输入或者用作快捷键的修饰键. 打开“系统偏好设置”,点击“键盘→键盘 ...
- Maven 项目中的 pom.xml 文件内容说明
下面是一个比较全面的 POM 文件的结构,当然常用的并不需要这么多配置,视自己的项目需求而定. <project xmlns="http://maven.apache.org/POM/ ...
- WCF透明代理类,动态调用,支持async/await
我们希望WCF客户端调用采用透明代理方式,不用添加服务引用,也不用Invoke的方式,通过ChannelFactory<>动态产生通道,实现服务接口进行调用,并且支持async/await ...
- 使用autogen生成应用程序遇到问题及解决方法
从github上下载的代码,运行autogen.sh的时候,上报错误: $ ./autogen.sh --prefix=/usr./autogen.sh: 10: ./autogen.sh: auto ...
- Thymeleaf教程入门到深入1:基础介绍
1 介绍 1.1 简介 Thymeleaf是一个用于Web和独立Java环境的模板引擎,能够处理HTML.XML.JavaScript.CSS甚至纯文本.能轻易的与Spring MVC等Web框架进行 ...
- Linux中matplotlib 中文显示问题解决
1.下载下载中文 arial unicode ms 字体到 /home 目录 2. 拷贝字体到 usr/share/fonts 下: sudo cp ~/arial\ unicode\ ms.ttf ...
- 【sping揭秘】22、事务管理
有关事务的楔子 什么是事务??? 事务就是以可控的方式对数据资源进行访问的一组操作. 事务本身持有四个限定属性 原子性,一致性,隔离性,持久性 事务家族 Resource Manager RM,负责 ...
- vector源码3(参考STL源码--侯捷):pop_back、erase、clear、insert
vector源码1(参考STL源码--侯捷) vector源码2(参考STL源码--侯捷):空间分配.push_back vector源码(参考STL源码--侯捷)-----空间分配导致迭代器失效 v ...
- Asp.Net Core微信服务中间件-.NetCore2.1
又封周末,闲暇无聊,随手写了一个关于微信公众号服务的中间件,基于.NetCore2.1.服务类库采用.Net Standard2.0,兼容.net 4.6.1. 整体思路是,设计一个中间件,提供微信消 ...