论文部分内容阅读
摘要:this在C++中称为this指针,它代表了当前实例的内存地址;在C#中称为this引用。使用this可以在类中方便地访问到本类的当前实例,也可以将本类的当前实例方便地传送到另一个类中去。通过多个例子,说明了在C++和C#中显示或隐含使用this的方法,这些方法是编辑中的常用技巧。
关键词:类;面向对象编程;this;指针;引用
中图分类号:TP312文献标识码:A 文章编号:1009-3044(2007)04-11052-03
1 引言
this关键字在C++和C#程序中既随处可见,又无处不在:“随处可见”表明在程序中常常会看到它;“无处不在”说的是在每个类代码中都隐含有它。可以毫不夸张的说,没有理解“this”就没有完全理解类,因为你的类中或隐或现总会有若干个this。“this”到底是什么?它在程序中有什么作用?如何正确地使用它?搞清这些问题对于理解类的基本概念,提高面向对象程序设计的编程技巧大有裨益。
2 什么是this
常常会将“this”简单地理解为“这个”或“我自己”,大致相当于VB中的“Me”。这样理解过于笼统,应进一步明确为“我这个实例(或称当前实例)”,而不是“我这个类”或“我这个数据”等。
C++把this称为this指针,它代表了当前实例的内存地址,通过它可以访问当前实例的数据成员,通常写成“this->成员”或“*this. 成员”的形式。
C#把数据分为值类型和引用类型两大类,类实例属于引用类型,它在栈上存储实例的引用,在堆上存储实例的实际数据,因而把this称为this引用。访问当前实例的成员时,使用“.”操作符,在程序中应写成“this.成员”的形式。
3 this指针
C++用this指针来代表当前实例的内存地址,有了这个地址,就可以方便地访问到当前实例的所有成员。C++约定可以隐含或显式使用this。
3.1 隐含的this指针
来看一个十分简单的C++类:
学习过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;
cout<<”全局x=”<<::x<<”,”;
cout<<”成员x=”<x<<”,”;//此处this强调当前实例
cout<<”局部x=”< 运行结果为:全局x=1,成员x=2,局部x=3。
3.2.2 this作函数的实参
下例中以this指针作函数调用的实参,将当前实例的地址(自身地址)传入函数内。
//向B类的成员函数传入A类的实例地址
{p1->display(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 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#不支持全局变量的使用,因而类之间信息的交换采用了将类的当前实例的引用传送到另一个类中的手段来实现。这段程序具有普遍的意义。
参考文献:
[1]钱能.C++程序设计教程[M].北京:清华大学出版社,1999.
[2]张国锋.C++语言及其程序设计教程[M].北京:电子工业出版社,2001.
[3]美James P.Cohoon,等,刘瑞挺,译.C++程序设计[M].北京:电子工业出版社,2002.
[4]陈志泊,王春玲.面向对象程序设计____C++[M].北京:人民邮电出版社,2004.
[5](美)Simon Robinson,等著,康博,译.C#高级编程[M].北京:清华大学出版社,2002.
[6]黎晓东,李华飚,等.精通C#编程[M].北京 科学出版社,2002.
[7]田原.C#程序设计[M].北京:交通大学出版社,2005.
[8]杨宏伟,李晶.C#程序员开发手册[M].北京:希望电子出版社,2005.
[9]唐耀主.C#程序设计实用教程[M].北京:中国水利水电出版社,2005.
本文中所涉及到的图表、注解、公式等内容请以PDF格式阅读原文。
关键词:类;面向对象编程;this;指针;引用
中图分类号:TP312文献标识码:A 文章编号:1009-3044(2007)04-11052-03
1 引言
this关键字在C++和C#程序中既随处可见,又无处不在:“随处可见”表明在程序中常常会看到它;“无处不在”说的是在每个类代码中都隐含有它。可以毫不夸张的说,没有理解“this”就没有完全理解类,因为你的类中或隐或现总会有若干个this。“this”到底是什么?它在程序中有什么作用?如何正确地使用它?搞清这些问题对于理解类的基本概念,提高面向对象程序设计的编程技巧大有裨益。
2 什么是this
常常会将“this”简单地理解为“这个”或“我自己”,大致相当于VB中的“Me”。这样理解过于笼统,应进一步明确为“我这个实例(或称当前实例)”,而不是“我这个类”或“我这个数据”等。
C++把this称为this指针,它代表了当前实例的内存地址,通过它可以访问当前实例的数据成员,通常写成“this->成员”或“*this. 成员”的形式。
C#把数据分为值类型和引用类型两大类,类实例属于引用类型,它在栈上存储实例的引用,在堆上存储实例的实际数据,因而把this称为this引用。访问当前实例的成员时,使用“.”操作符,在程序中应写成“this.成员”的形式。
3 this指针
C++用this指针来代表当前实例的内存地址,有了这个地址,就可以方便地访问到当前实例的所有成员。C++约定可以隐含或显式使用this。
3.1 隐含的this指针
来看一个十分简单的C++类:
学习过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;
cout<<”全局x=”<<::x<<”,”;
cout<<”成员x=”<
cout<<”局部x=”<
3.2.2 this作函数的实参
下例中以this指针作函数调用的实参,将当前实例的地址(自身地址)传入函数内。
//向B类的成员函数传入A类的实例地址
{p1->display(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 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#不支持全局变量的使用,因而类之间信息的交换采用了将类的当前实例的引用传送到另一个类中的手段来实现。这段程序具有普遍的意义。
参考文献:
[1]钱能.C++程序设计教程[M].北京:清华大学出版社,1999.
[2]张国锋.C++语言及其程序设计教程[M].北京:电子工业出版社,2001.
[3]美James P.Cohoon,等,刘瑞挺,译.C++程序设计[M].北京:电子工业出版社,2002.
[4]陈志泊,王春玲.面向对象程序设计____C++[M].北京:人民邮电出版社,2004.
[5](美)Simon Robinson,等著,康博,译.C#高级编程[M].北京:清华大学出版社,2002.
[6]黎晓东,李华飚,等.精通C#编程[M].北京 科学出版社,2002.
[7]田原.C#程序设计[M].北京:交通大学出版社,2005.
[8]杨宏伟,李晶.C#程序员开发手册[M].北京:希望电子出版社,2005.
[9]唐耀主.C#程序设计实用教程[M].北京:中国水利水电出版社,2005.
本文中所涉及到的图表、注解、公式等内容请以PDF格式阅读原文。