详解C++中的成员访问运算符和指针到成员运算符
成员访问运算符:.和->
语法
postfix-expression
.name
postfix-expression–>name
备注
成员访问运算符.和->用来引用结构、联合和类的成员。成员访问表达式具有选定成员的值和类型。
有两种形式的成员访问表达式:
在第一种形式中,postfix-expression表示结构、类或联合类型的值,name为指定的结构、联合或类的成员命名。运算的值是name的值且为左值(如果postfix-expression是左值)。
在第二种形式中,postfix-expression表示指向结构、联合或类的指针,name为指定的结构、联合或类的成员命名。该值是name的值且是左值。–>运算符取消引用该指针。因此,表达式e–>member和(*e).member(其中,e表示指针)会产生相同的结果(重载运算符–>或*的情况除外)。
以下示例演示成员访问运算符的两种形式。
//expre_Selection_Operator.cpp //compilewith:/EHsc #include<iostream> usingnamespacestd; structDate{ Date(inti,intj,intk):day(i),month(j),year(k){} intmonth; intday; intyear; }; intmain(){ Datemydate(1,1,1900); mydate.month=2; cout<<mydate.month<<"/"<<mydate.day <<"/"<<mydate.year<<endl; Date*mydate2=newDate(1,1,2000); mydate2->month=2; cout<<mydate2->month<<"/"<<mydate2->day <<"/"<<mydate2->year<<endl; deletemydate2; }
这样的话出来的两个值分别为:
2/1/1900 2/1/2000
指针到成员运算符:.*和->*
语法
expression.*expression
expression–>*expression
备注
指向成员的指针运算符(.*和–>*)返回表达式左侧上指定的对象的特定类成员的值。右侧必须指定该类的成员。下面的示例演示如何使用这些运算符:
//expre_Expressions_with_Pointer_Member_Operators.cpp //compilewith:/EHsc #include<iostream> usingnamespacestd; classTestpm{ public: voidm_func1(){cout<<"m_func1\n";} intm_num; }; //Definederivedtypespmfnandpmd. //Thesetypesarepointerstomembersm_func1()and //m_num,respectively. void(Testpm::*pmfn)()=&Testpm::m_func1; intTestpm::*pmd=&Testpm::m_num; intmain(){ TestpmATestpm; Testpm*pTestpm=newTestpm; //Accessthememberfunction (ATestpm.*pmfn)(); (pTestpm->*pmfn)();//Parenthesesrequiredsince*binds //lesstightlythanthefunctioncall. //Accessthememberdata ATestpm.*pmd=1; pTestpm->*pmd=2; cout<<ATestpm.*pmd<<endl <<pTestpm->*pmd<<endl; deletepTestpm; } Output m_func1 m_func1
结果分别为:
1 2
在前面的示例中,指向成员的指针pmfn用于调用成员函数m_func1。另一个指向成员的指针pmd用于访问m_num成员。
二元运算符.*将其第一操作数(必须是类类型的对象)与其第二操作数(必须是指向成员的指针类型)组合在一起。
二元运算符–>*将其第一操作数(必须是指向类类型的对象的指针)与其第二操作数(必须是指向成员的指针类型)组合在一起。
在包含.*运算符的表达式中,第一操作数必须是类类型且可访问,而指向第二操作数中指定的成员的指针或可访问类型的成员的指针明确从该类派生并且可供该类访问。
在包含–>*运算符的表达方式中,第一操作数必须是第二操作数中指定的类型的“指向类类型的指针”或明确地从该类派生的类型。
考虑以下类和程序段:
//expre_Expressions_with_Pointer_Member_Operators2.cpp //C2440expected classBaseClass{ public: BaseClass();//Baseclassconstructor. voidFunc1(); }; //DeclareapointertomemberfunctionFunc1. void(BaseClass::*pmfnFunc1)()=&BaseClass::Func1; classDerived:publicBaseClass{ public: Derived();//Derivedclassconstructor. voidFunc2(); }; //DeclareapointertomemberfunctionFunc2. void(Derived::*pmfnFunc2)()=&Derived::Func2; intmain(){ BaseClassABase; DerivedADerived; (ABase.*pmfnFunc1)();//OK:definedforBaseClass. (ABase.*pmfnFunc2)();//Error:cannotusebaseclassto //accesspointerstomembersof //derivedclasses. (ADerived.*pmfnFunc1)();//OK:Derivedisunambiguously //derivedfromBaseClass. (ADerived.*pmfnFunc2)();//OK:definedforDerived. }
指向成员的指针运算符.*或–>*的结果是在指向成员的指针的声明中指定的类型的对象或函数。因此,在前面的示例中,表达式ADerived.*pmfnFunc1()的结果是指向返回void的函数的指针。如果第二操作数是左值,则此结果为左值。
System_CAPS_note注意
如果某个指向成员的指针运算符的结果是函数,则该结果只能用作函数调用运算符的操作数。