Item 28: do not return the internal handle of the object. Valid C ++ notes
Item 28: Avoid returning handles to object internals.
Do not return the handle of the Private member of the object. Here the "handle" (handle) includes references, pointers, and iterators. In this way, the class encapsulation andconst
More functionsconst
And avoid creating empty references (dangling handles ).
For convenience, the three types of handles are collectively referred to as pointers in the following article.
Returns the pointer of a private member.
Let's review the behavior of class member pointers before continuing Scott Meyers's discussion. First, if no restriction is imposed, returning the pointer of the Private member will completely expose the private member. For example:
Class Rectangle {int _ left, _ top; public: int & left () {return _ left ;}}; Rectangle rec; rec. left () = 3; // rec. _ left modified
In fact, this is enough to show that the returned private member pointer is equivalent to completely exposing the private member.
Expose private members as constants
If it is to protect private members from being modified, it is only to allow external users to access_left
, You can setleft()
Declaredconst
:
int& left() const{ return _left; }
The above code is still problematic ~ The compiler produces the following errors:
error: binding of reference to type 'int' to a value of type 'const int' drops qualifiers
This is because the constant method cannot modify the current object, and its return value should also beconst
. It should be written as follows:
const int& left() const{ return _left; }
The returned value declaresconst
The internal variable is compiled incorrectly. We successfully opened internal variables while preventing internal variables from being modified. But the problem persists! Remember? The constant of C ++ is defined as bitwise constness, so long as the current object is not modified, it is regarded as a constant. So if weleft
Andtop
Outside the existing class, the type check of the return value of the constant method will become invalid. For example, if the data existsPoint
Inside:
Class Point {public: int left, right ;}; class Rectangle {Point * p; public: int & left () const {return p-> left ;}};... const Rectangle rec; rec. left () = 3; // rec is a const object, but we can modify it ~
NowRectangle
The size issizeof(void*)
(Pointer size), that isp->left
It is not in the memory of this object, so the return value of the constant method can not be declaredconst
. Then the customer can returnleft
To modify the private member of the object. Therefore, returning the internal pointer of the object will lead to the constant Methodconst
The property is damaged. The root cause is the bitwise constness syntax check style of C ++.
Note that ifp
DeclaredPoint
RatherPoint*
,p->left
The compiler will requireleft() const
The returned value isconst int&
.
Null Pointer
You may have noticed that we can slightly improve the code above to implement write protection for private members. Since the bitwise constness compiler does not provide a type check, we manually limit the returned valueconst
You can:
const int& left() const{ return p->left; }
In many cases, the problem is solved in this way, for exampleoperator[]() const
. However, the subscript operator is only a special case. Generally, we do not return internal pointers. Because the returned pointer has the same lifecycle as the owner object, the returned pointer is easily suspended. For exampleRectangle
Ofbounding
Function:
const Rectangle bounding();
We want to getRectangle
Ofleft
, May write as follows:
const int& left = bounding().left();
Where is the problem?left
Suspended, not maintainedleft
Value! Becausebounding()
The returned object is not assigned to any variable. It is a temporary object. The temporary object is destroyed immediately after the statement is executed, and the reference of the Private member will also become invalid.