C++this指针问题.docx
《C++this指针问题.docx》由会员分享,可在线阅读,更多相关《C++this指针问题.docx(9页珍藏版)》请在冰豆网上搜索。
![C++this指针问题.docx](https://file1.bdocx.com/fileroot1/2023-1/9/68c74d4b-8b23-4a33-81bf-fe8eff5dd936/68c74d4b-8b23-4a33-81bf-fe8eff5dd9361.gif)
C++this指针问题
C++中this指针的用法.
2008-07-0413:
5610171人阅读评论(33)收藏举报
this指针只能在一个类的成员函数中调用,它表示当前对象的地址。
下面是一个例子:
voidDate:
:
setMonth(intmn)
{
month=mn;//这三句是等价的this->month=mn;
(*this).month=mn;
}
1.this只能在成员函数中使用。
全局函数,静态函数都不能使用this。
实际上,成员函数默认第一个参数为T*constregisterthis。
如:
classA{public:
intfunc(intp){}};
其中,func的原型在编译器看来应该是:
intfunc(A*constregisterthis,intp);
2.由此可见,this在成员函数的开始前构造的,在成员的结束后清除。
这个生命周期同任一个函数的参数是一样的,没有任何区别。
当调用一个类的成员函数时,编译器将类的指针作为函数的this参数传递进去。
如:
Aa;
a.func(10);
此处,编译器将会编译成:
A:
:
func(&a,10);
嗯,看起来和静态函数没差别,对吗?
不过,区别还是有的。
编译器通常会对this指针做一些优化的,因此,this指针的传递效率比较高--如vc通常是通过ecx寄存器来传递this参数。
3.回答
#1:
this指针是什么时候创建的?
this在成员函数的开始执行前构造的,在成员的执行结束后清除。
#2:
this指针存放在何处?
堆,栈,全局变量,还是其他?
this指针会因编译器不同,而放置的位置不同。
可能是栈,也可能是寄存器,甚至全局变量。
#3:
this指针如何传递给类中函数的?
绑定?
还是在函数参数的首参数就是this指针.那么this指针又是如何找到类实例后函数的?
this是通过函数参数的首参数来传递的。
this指针是在调用之前生成的。
类实例后的函数,没有这个说法。
类在实例化时,只分配类中的变量空间,并没有为函数分配空间。
自从类的函数定义完成后,它就在那儿,不会跑的。
#4:
this指针如何访问类中变量的/?
如果不是类,而是结构的话,那么,如何通过结构指针来访问结构中的变量呢?
如果你明白这一点的话,那就很好理解这个问题了。
在C++中,类和结构是只有一个区别的:
类的成员默认是private,而结构是public。
this是类的指针,如果换成结构,那this就是结构的指针了。
#5:
我们只有获得一个对象后,才能通过对象使用this指针,如果我们知道一个对象this指针的位置可以直接使用吗?
this指针只有在成员函数中才有定义。
因此,你获得一个对象后,也不能通过对象使用this指针。
所以,我们也无法知道一个对象的this指针的位置(只有在成员函数里才有this指针的位置)。
当然,在成员函数里,你是可以知道this指针的位置的(可以&this获得),也可以直接使用的。
#6:
每个类编译后,是否创建一个类中函数表保存函数指针,以便用来调用函数?
普通的类函数(不论是成员函数,还是静态函数),都不会创建一个函数表来保存函数指针的。
只有虚函数才会被放到函数表中。
但是,既使是虚函数,如果编译器能明确知道调用的是哪个函数,编译器就不会通过函数表中的指针来间接调用,而是会直接调用该函数。
#7:
这些编译器如何做到的?
8:
能否模拟实现?
知道原理后,这两个问题就很容易理解了。
其实,模拟实现this的调用,在很多场合下,很多人都做过。
例如,系统回调函数。
系统回调函数有很多,如定时,线程啊什么的。
举一个线程的例子:
classA{
intn;
public:
staticvoidrun(void*pThis){
A*this_=(A*)pThis;
this_->process();
}
voidprocess(){}
};
main(){
Aa;
_beginthread(A:
:
run,0,&a);
}
这里就是定义一个静态函数来模拟成员函数。
也有许多C语言写的程序,模拟了类的实现。
如freetype库等等。
其实,有用过C语言的人,大多都模拟过。
只是当时没有明确的概念罢了。
如:
typedefstructstudent{
intage;
intno;
intscores;
}Student;
voidinitStudent(Student*pstudent);
voidaddScore(Student*pstudent,intscore);
...
如果你把pstudent改成this,那就一样了。
它相当于:
classStudent{
public:
intage;intno;intscores;
voidinitStudent();
voidaddScore(intscore);
}
const常量可以有物理存放的空间,因此是可以取地址的
///this指针是在创建对象前创建.this指针放在栈上,在编译时刻已经确定.
并且当一个对象创建后,并且运行整个程序运行期间只有一个this指针.
2011-09-2414:
54
C++中this指针的使用
一、关于this指针的一个精典回答
当你进入一个房子后,
你可以看见桌子、椅子、地板等,
但是房子你是看不到全貌了。
对于一个类的实例来说,
你可以看到它的成员函数、成员变量,
但是实例本身呢?
this是一个指针,它时时刻刻指向你这个实例本身。
二、从语言层次上讲
this指针作为一个隐含参数传递给非静态成员函数,用以指向该成员函数所属类所定义的对象。
当不同的对象调用同一个类的成员函数代码时,编译器会依据该成员函数的this指针所指向的不同对象来确定应该引用哪个对象的数据成员。
三、类的this指针的特点
(1)this只能在成员函数中使用。
全局函数、静态函数都不能使用this。
实际上,成员函数默认第一个参数为T*constthis。
如:
classA
{
public:
intfunc(intp)
{
}
};
其中,func的原型在编译器看来应该是:
intfunc(A*constthis,intp);
(2)由此可见,this在成员函数的开始前构造,在成员函数的结束后清除。
这个生命周期同任何一个函数的参数是一样的,没有任何区别。
当调用一个类的成员函数时,编译器将该类的指针作为函数的this参数传递进去。
如:
Aa;
a.func(10);
此处,编译器将会编译成:
A:
:
func(&a,10);
看起来和静态函数没差别,对吗?
不过,区别还是有的。
编译器通常会对this指针做一些优化,因此,this指针的传递效率比较高(如VC通常是通过ecx寄存器传递this参数的)。
(3)几个this指针的易混问题。
A.this指针是什么时候创建的?
this在成员函数的开始执行前构造,在成员的执行结束后清除。
但是如果class或者struct里面没有方法的话,它们是没有构造函数的,只能当做C的struct使用。
采用TYPExx的方式定义的话,在栈里分配内存,这时候this指针的值就是这块内存的地址。
采用new的方式创建对象的话,在堆里分配内存,new操作符通过eax返回分配的地址,然后设置给指针变量。
之后去调用构造函数(如果有构造函数的话),这时将这个内存块的地址传给ecx,之后构造函数里面怎么处理请看上面的回答。
B.this指针存放在何处?
堆、栈、全局变量,还是其他?
this指针会因编译器不同而有不同的放置位置。
可能是栈,也可能是寄存器,甚至全局变量。
在汇编级别里面,一个值只会以3种形式出现:
立即数、寄存器值和内存变量值。
不是存放在寄存器就是存放在内存中,它们并不是和高级语言变量对应的。
C.this指针是如何传递类中的函数的?
绑定?
还是在函数参数的首参数就是this指针?
那么,this指针又是如何找到“类实例后函数的”?
大多数编译器通过ecx寄存器传递this指针。
事实上,这也是一个潜规则。
一般来说,不同编译器都会遵从一致的传参规则,否则不同编译器产生的obj就无法匹配了。
在call之前,编译器会把对应的对象地址放到eax中。
this是通过函数参数的首参来传递的。
this指针在调用之前生成,至于“类实例后函数”,没有这个说法。
类在实例化时,只分配类中的变量空间,并没有为函数分配空间。
自从类的函数定义完成后,它就在那儿,不会跑的。
D.this指针是如何访问类中的变量的?
如果不是类,而是结构体的话,那么,如何通过结构指针来访问结构中的变量呢?
如果你明白这一点的话,就很容易理解这个问题了。
在C++中,类和结构是只有一个区别的:
类的成员默认是private,而结构是public。
this是类的指针,如果换成结构,那this就是结构的指针了。
E.我们只有获得一个对象后,才能通过对象使用this指针。
如果我们知道一个对象this指针的位置,可以直接使用吗?
this指针只有在成员函数中才有定义。
因此,你获得一个对象后,也不能通过对象使用this指针。
所以,我们无法知道一个对象的this指针的位置(只有在成员函数里才有this指针的位置)。
当然,在成员函数里,你是可以知道this指针的位置的(可以通过&this获得),也可以直接使用它。
F.每个类编译后,是否创建一个类中函数表保存函数指针,以便用来调用函数?
普通的类函数(不论是成员函数,还是静态函数)都不会创建一个函数表来保存函数指针。
只有虚函数才会被放到函数表中。
但是,即使是虚函数,如果编译器能明确知道调用的是哪个函数,编译器就不会通过函数表中的指针来间接调用,而是会直接调用该函数。
本文摘自《程序员面试宝典》
置:
首页>>编程技术库
C++中this指针的使用介绍
[大][中][小]发布人:
圣才学习网发布日期:
2012-03-2409:
41共163人浏览
this指针是一个特殊的指针,当类的某个非静态的成员函数在执行时,就会存在this指针。
它指向类的一个对象,且这个对象的某个成员函数正在被调用。
this指针的名字始终是this,而且总是作为隐含参数传递给每一个被声明的成员函数,例如:
1.voidDate:
:
myFunc(Date*this);
实际编程时函数的声明不需要包含这个参数。
当程序中调用某个对象的成员函数时,编译器会把该对象的地址加入到参数列表中,感觉上就好象函数采用了上面所示的声明,并且是用如下方式来调用的:
1.dt.myFunc(&dt);
静态成员函数不存在this指针。
当调用某个对象的成员函数时,编译器把对象的地址传递给this指针,然后再调用该函数。
因此,成员函数你对任何成员的调用实际上都隐式地使用了this指针。
1.以this指针作为返回值
使this指针可以允许成员函数返回调用对象给调用者。
前面的程序中重载赋值运算符没有返回值,因此不能用如下的形式对字符串进行赋值:
1.a=b=c;
为了使重载的类赋值机制也能这样方便,必须让赋值函数返回赋值的结果,在这里就是目标对象。
当赋值函数执行时,其返回值也恰好是this指针所指的内容。
下面的程序对前面那个程序进行了修改,让重载赋值运算符返回了一个Date对象的引用。
1.#include\"iostream.h\"
2.#include\"string.h\"
3.classDate
4.{
5.intmo,da,yr;
6.char*month;
7.public:
8.Date(intm=0,intd=0,inty=0);
9.~Date();
10.voidoperator=(constDate&);
11.voiddisplay()const;
12.};
13.Date:
:
Date(intm,intd,inty)
14.{
15.staticchar*mos[]=
16.{
17.\"January\",\"February\",\"March\",\"April\",\"May\",\"June\",
18.\"July\",\"August\",\"September\",\"October\",\"November\",\"December\"
19.};
20.mo=m;da=d;yr=y;
21.if(m!
=0)
22.{
23.month=newchar[strlen(mos[m-1])+1];
24.strcpy(month,mos[m-1]);
25.}
26.elsemonth=0;
27.}
28.Date:
:
~Date()
29.{
30.delete[]month;
31.}
32.
33.voidDate:
:
display()const
34.{
35.if(month!
=0)cout<36.}
37.
38.voidDate:
:
operator=(constDate&dt)
39.{
40.if(this!
=&dt)
41.{
42.mo=dt.mo;
43.da=dt.da;
44.yr=dt.yr;
45.delete[]month;
46.if(dt.month!
=0)
47.{
48.month=newchar[std:
:
strlen(dt.month)+1];
49.std:
:
strcpy(month,dt.month);
50.}
51.elsemonth=0;
52.}
53.return*this;
54.}
55.intmain()
56.{
57.Datebirthday(8,11,1979);
58.Dateoldday,newday;
59.oldday=newday=birthday;
60.birthday.display();
61.oldday.display();
62.newday.display();
63.return0;
64.}
2.在链表中使用this指针
在应用程序中,如果数据结构里有指向自身类型的成员,那么使用this指针会提供更多的方便。
下面的程序中建立了一个类ListEntry的链表。
1.#include\"iostream.h\"
2.#include\"string.h\"
3.
4.classListEntry
5.{
6.char*listvalue;
7.ListEntry*preventry;
8.public:
9.ListEntry(char*);
10.~ListEntry(){delete[]listvalue;}
11.ListEntry*PrevEntry()const{returnpreventry;};
12.voiddisplay()const{cout<13.voidAddEntry(ListEntry&le){le.preventry=this;}
14.};
15.
16.ListEntry:
:
ListEntry(char*s)
17.{
18.listvalue=newchar[strlen(s)+1];
19.strcpy(listvalue,s);
20.preventry=0;
21.}
22.
23.intmain()
24.{
25.ListEntry*prev=0;
26.
27.while
(1)
28.{
29.cout<\";
30.charname[25];
31.cin>>name;
32.if(strncmp(name,\"end\",3)==0)break;
33.ListEntry*list=newListEntry(name);
34.if(prev!
=0)prev->AddEntry(*list);
35.prev=list;
36.}
37.
38.while(prev!
=0)
39.{
40.prev->display();
41.ListEntry*hold=prev;
42.prev=prev->PrevEntry();
43.deletehold;
44.}
45.return0;
46.}
程序运行时,会提示输入一串姓名,当输入完毕后,键入\"end\",然后程序会逆序显示刚才输入的所有姓名。
程中ListEntry类含有一个字符串和一个指向前一个表项的指针。
构造函数从对中获取内存分配给字符串,并把字符串的内容拷贝到内存,然后置链接指针为NULL。
析构函数将释放字符串所占用的内存。
成员函数PrevEntry()返回指向链表前一个表项的指针。
另一个成员函数显示当前的表项内容。
成员函数AddEntry(),它把this指针拷贝给参数的preventry指针,即把当前表项的地址赋值给下一个表项的链接指针,从而构造了一个链表。
它并没有改变调用它的listEntry对象的内容,只是把该对象的地址赋给函数的参数所引用的那个ListEntry对象的preventry指针,尽管该函数不会修改对象的数据,但它并不是常量型。
这是因为,它拷贝对象的地址this指针的内容给一个非长常量对象,而编译器回认为这个非常量对象就有可能通过拷贝得到的地址去修改当前对象的数据,因此AddEntry()函数在声明时不需要用const。
希望通过以上内容的介绍,能够给你带来帮助。