C++编程指向成员的指针以及this指针的基本使用指南
指向成员的指针
指向成员的指针的声明是指针声明的特例。使用以下序列来声明它们:
[storage-class-specifiers][cv-qualifiers]type-specifiers[ms-modifier] qualified-name::*[cv-qualifiers]identifier [=&qualified-name::member-name];
声明说明符:
- 可选存储类说明符。
- 可选const和/或volatile说明符。
- 类型说明符:类型的名称。这是要指向的成员的类型,而不是类。
声明符:
- 可选的Microsoft专用修饰符。
- 包含要指向的成员的类的限定名。
- ::运算符。
- *运算符。
- 可选const和/或volatile说明符。
- 命名指向成员的指针的标识符。
可选的初始值设定项:
- =运算符。
- &运算符。
- 类的限定名。
- ::运算符。
- 适当类型的类的非静态成员的名称。
像往常一样,允许在单个声明中使用多个声明符(以及任何关联的初始值设定项)。
指向类的成员的指针与普通指针不同,因为它有该成员的类型的类型信息和该成员所属的类的类型信息。常规指针只标识内存中的一个对象或只具有其地址。指向类的某个成员的指针标识类的所有实例中的该成员。以下示例声明类、Window和一些指向成员数据的指针。
//pointers_to_members1.cpp classWindow { public: Window();//Defaultconstructor. Window(intx1,inty1,//Constructorspecifying intx2,inty2);//windowsize. boolSetCaption(constchar*szTitle);//Setwindowcaption. constchar*GetCaption();//Getwindowcaption. char*szWinCaption;//Windowcaption. }; //DeclareapointertothedatamemberszWinCaption. char*Window::*pwCaption=&Window::szWinCaption; intmain() { }
在前面的示例中,pwCaption是一个指针,它指向具有Windowchar*类型的类的任何成员。类型pwCaption不是char*Window::*。下一个代码片段将指针声明为SetCaption和GetCaption成员函数。
constchar*(Window::*pfnwGC)()=&Window::GetCaption; bool(Window::*pfnwSC)(constchar*)=&Window::SetCaption;
指针pfnwGC和pfnwSC分别指向GetCaption类的SetCaption和Window。以下代码直接使用指向成员pwCaption的指针将信息复制到窗口标题:
WindowwMainWindow; Window*pwChildWindow=newWindow; char*szUntitled="Untitled-"; intcUntitledLen=strlen(szUntitled); strcpy_s(wMainWindow.*pwCaption,cUntitledLen,szUntitled); (wMainWindow.*pwCaption)[cUntitledLen-1]='1';//sameas //wMainWindow.SzWinCaption[cUntitledLen-1]='1'; strcpy_s(pwChildWindow->*pwCaption,cUntitledLen,szUntitled); (pwChildWindow->*pwCaption)[cUntitledLen-1]='2';//sameas//pwChildWindow->szWinCaption[cUntitledLen-1]='2';
.*和–>*运算符(指向成员的指针运算符)的区别在于.*运算符选择成员给定的对象或对象引用,而–>*运算符通过指针选择成员。(有关这些运算符的更多信息,请参阅使用指向成员的指针运算符的表达式。)
指向成员的指针运算符的结果是成员的类型-本例中为char*。
以下代码片段使用指向成员的指针调用成员函数GetCaption和SetCaption:
//Allocateabuffer. enum{ sizeOfBuffer=100 }; charszCaptionBase[sizeOfBuffer]; //Copythemainwindowcaptionintothebuffer //andappend"[View1]". strcpy_s(szCaptionBase,sizeOfBuffer,(wMainWindow.*pfnwGC)()); strcat_s(szCaptionBase,sizeOfBuffer,"[View1]"); //Setthechildwindow'scaption. (pwChildWindow->*pfnwSC)(szCaptionBase);
针对指向成员的指针的限制
静态成员的地址不是指向成员的指针。它是指向静态成员的一个实例的常规指针。由于给定类的所有对象只存在一个静态成员实例,因此可以使用普通的address-of(&)和取消引用(*)运算符。
指向成员和虚函数的指针
通过指向成员函数的指针调用虚函数就如同直接调用函数一样;将在v表中查找并调用正确的函数。
一直以来,虚函数工作的关键是通过指向基类的指针来调用它们。(有关虚函数的详细信息,请参阅虚函数。)
以下代码演示如何通过指向成员函数的指针调用虚函数:
//virtual_functions.cpp //compilewith:/EHsc #include<iostream> usingnamespacestd; classBase { public: virtualvoidPrint(); }; void(Base::*bfnPrint)()=&Base::Print; voidBase::Print() { cout<<"PrintfunctionforclassBase\n"; } classDerived:publicBase { public: voidPrint();//Printisstillavirtualfunction. }; voidDerived::Print() { cout<<"PrintfunctionforclassDerived\n"; } intmain() { Base*bPtr; BasebObject; DeriveddObject; bPtr=&bObject;//SetpointertoaddressofbObject. (bPtr->*bfnPrint)(); bPtr=&dObject;//SetpointertoaddressofdObject. (bPtr->*bfnPrint)(); } //Output:PrintfunctionforclassBase PrintfunctionforclassDerived
this指针
this指针是只能在class、struct或union类型的非静态成员函数中访问的指针。它指向为其调用成员函数的对象。静态成员函数没有this指针。
语法
this this->member-identifier
备注
对象的this指针不是对象的一部分;它没有在对象上的sizeof语句的结果中反映。相反,当对某个对象调用非静态成员函数时,该对象的地址将由编译器作为隐藏的参数传递给函数。例如,以下函数调用:
myDate.setMonth(3);
可以按以下方式解释:
setMonth(&myDate,3);
对象的地址可从成员函数的内部作为this指针提供。this的大多数使用都是隐式的。在引用类的成员时显式使用this是合法的,但没有必要。例如:
voidDate::setMonth(intmn) { month=mn;//Thesethreestatements this->month=mn;//areequivalent (*this).month=mn; }
表达式*this通常用于从成员函数返回当前对象:
return*this;
this指针还用于防止自引用:
if(&Object!=this){ //donotexecuteincasesofself-reference
注意
由于this指针无法更改,因此不允许对this赋值。C++的早期实现允许对this赋值。
this指针有时可直接使用-例如,当操作自引用数据结构,而其中需要当前对象的地址时。
//this_pointer.cpp //compilewith:/EHsc #include<iostream> #include<string.h> usingnamespacestd; classBuf { public: Buf(char*szBuffer,size_tsizeOfBuffer); Buf&operator=(constBuf&); voidDisplay(){cout<<buffer<<endl;} private: char*buffer; size_tsizeOfBuffer; }; Buf::Buf(char*szBuffer,size_tsizeOfBuffer) { sizeOfBuffer++;//accountforaNULLterminator buffer=newchar[sizeOfBuffer]; if(buffer) { strcpy_s(buffer,sizeOfBuffer,szBuffer); sizeOfBuffer=sizeOfBuffer; } } Buf&Buf::operator=(constBuf&otherbuf) { if(&otherbuf!=this) { if(buffer) delete[]buffer; sizeOfBuffer=strlen(otherbuf.buffer)+1; buffer=newchar[sizeOfBuffer]; strcpy_s(buffer,sizeOfBuffer,otherbuf.buffer); } return*this; } intmain() { BufmyBuf("mybuffer",10); BufyourBuf("yourbuffer",12); //Display'mybuffer' myBuf.Display(); //assignmentopperator myBuf=yourBuf; //Display'yourbuffer' myBuf.Display(); }
输出:
mybuffer yourbuffer
this指针的类型
通过const和关键字,可以在函数声明中修改volatilethis指针的类型。若要将函数声明为具有一个或多个关键字的特性,请将关键字添加到函数参数列表的后面。
请看以下示例:
//type_of_this_pointer1.cpp classPoint { unsignedX()const; }; intmain() { }
上面的代码声明一个成员函数X,其中,this指针被视为指向const对象的const指针。可以使用cv-mod-list选项的组合,但它们始终通过this修改指向的对象,而不是this指针本身。因此,以下声明将声明函数X;this指针是指向const对象的const指针:
//type_of_this_pointer2.cpp classPoint { unsignedX()const; }; intmain() { }
成员函数中this指针的类型由以下语法描述,其中,cv-qualifier-list是从成员函数声明符中确定的,可以是const和/或volatile,而class-type是类的名称:
[cv-qualifier-list]class-type*constthis
换言之,this始终是const指针;无法重新指派它。成员函数声明中使用的const或volatile限定符适用于由该函数范围中的this指向的类实例。
下表介绍了有关这些修饰符的工作方式的更多信息。
this修饰符的语义
修饰符 | |
---|---|
const | 不能更改数据成员;无法调用不是const的成员函数。 |
volatile | 每次访问成员数据时,都会从内存中加载该数据;禁用某些优化。 |
将const对象传递给不是const的成员函数是错误的。同样,将volatile对象传递给不是volatile的成员函数也是错误的。
声明为const的成员函数不能更改数据成员-在此类函数中,this指针是指向const对象的指针。
注意
构造函数和析构函数不能声明为const或volatile。但是,可以在const或volatile对象上调用它们。