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对象上调用它们。