Terms 21: Use const as possible
The benefit of using const is that it allows you to specify a constraint - some object cannot be modified - compiler
This constraint is implemented in particular. With const, you can notify the compiler and other programmers to remain unchanged.
As long as this is this, you have to use const, because you can make sure you can use the compiler.
This constraint is not destroyed.
The Const keyword is really unity. Outside the class, it can be used for global or name space constants (see clause 1
And 47), as well as static objects (partial objects within a file or block range). Inside the class, it can
For static and non-static members (see clause 12).
For pointers, you can specify the pointer itself as const, or you can specify the data referred to by the pointer to const, or both
At the same time, it is specified as const, and it is not specified as const:
Char * p = "Hello"; // Nonconst pointer,
// Nonconst data
Const char * p = "hello"; // non-const pointer,
// const data
Char * const p = "hello"; // constant,
// Nonconst data
Const char * const p = "hello"; // const pointer,
// const data
The syntax does not seem to change the multi-end. In general, you can draw a vertical line through the pointer statement in your mind.
The asterisk (*) position, if constant appears on the left side of the line, the data pointed to by the pointer is constant; if consT is
Now the right side of the line, the pointer itself is constant; if both of the Const online appears, both are constants.
In the case where the pointer is referred to as constant, some programmers like to put the const before the type name, some of the programmers are happy.
Huan put the const after the type name, the asterisk. Therefore, the following functions are the same type of parameter:
Class widget {...};
Void F1 (const widget * pw); // f1 is a point
// widget constant object pointer
Void F2 (Widget const * pw); // with F2
Because both representations exist in the actual code, they are used to these two forms.
Some powerful features of Const are based on its application in the function declaration. In a function declaration, Const can refer to
It is the return value of the function, or a parameter; for the member function, it can also refer to the entire function.
Let function return a constant value can often reduce the chance of making mistakes without reducing security and efficiency.
In fact, as explained in Terms 29, using consts for return values may increase the security and efficiency of a function,
Otherwise there will be a problem.
For example, see this declaration of the reasonable Operator * function introduced in terms 19:
Const Rational Operator * (Const Rational & LHS,
CONST RATIONAL & RHS);
Many programmers first see it will wonder: Why is the return result of Operator * Is a const object? because
If this is not the case, the user can do the following bad things:
Rational A, B, C;
...
(a * b) = c; // assign values for the results of A * B
I don't know why some of the programmers will assign a value directly to the two number of calculations, but I know: If A, B, and C are fixed types, this is obviously inevitable. A good user-defined type feature is that it will avoid
Free with unreasonable behavior that is incompatible with fixed types. For me, the value of the two counts is very
Not reasonable. Declare that the return value of Operator * is constant to prevent this, so this is correct
.
There is nothing special about const parameters to emphasize - their operations are the same as part of the local const. (But see
The Terms M19, the const parameter will result in a temporary object production. However, if the member function is const, that is
Another thing.
The purpose of the Const member function is of course to indicate which member function can be called on the Const object. But a lot
People ignore such a fact that only different member functions only in Const are overloaded. This is a weight of C
To character. Take later this String class:
Class string {
PUBLIC:
...
// Operator for non-Const objects []
Char & Operator [] (int position)
{Return Data [Position];
// Operator for Const object []
Const Char & Operator [] (int position) const
{Return Data [Position];
Private:
CHAR * DATA;
}
String S1 = "Hello";
COUT << S1 [0]; // Call non-Const
// String :: Operator []
Const string s2 = "world";
COUT << S2 [0]; // Call Const
// String :: Operator []
By overloading Operator [] and gives different versions, CONST and non-Const string can be performed.
Different processing:
String s = "Hello"; // Nonconst String object
Cout << s [0]; // correct - read one
// Nonconst string
s [0] = 'x'; // correct - write one
// Nonconst string
Const string cs = "world"; // const string object
COUT << CS [0]; // correct - read one
// const string
CS [0] = 'x'; // Error! - Write one
// const string
Also note that the error here is only related to the return value of the Operator []; Operator [] call itself no problem
. The reason for the error is that attempts to a const char & assignment, because the object being assigned is a const version.
The return value of the Operator [] function.
Also note that the return type of non-Const operator [] must be a reference to a char, CHAR itself is not
. If Operator [] really returns a simple char, the statement as shown below will not be compiled:
s [0] = 'x';
Because the return value of the function to modify a "return value is fixed type" is absolutely illegal. Even if it is legal, the C "is returned to the internal mechanism of the object" (see clause 22), S.DATA [
0] One copy will be modified, not S.Data [0] yourself, this is not the result you want.
Let us stop and see a basic principle. What is the exact meaning of a member function for Const? Two major
View: Const (Bitwise Constness) and Const (Conceptual) and Const (Conceptual)
Constness).
The persistence of Bitwise Constness believes that when and only when the member function does not modify any data member (static)
Except for data members), this member function is constant when any bit (bit) is not modified.
. Bitwise Constness's biggest advantage is to easily detect violations of Bitwise Constness regulations.
Event: The compiler is only used to find the assignment of a non-paid data member. In fact, Bitwise Constnes
S is the definition of C to const questions, and the Const member function is not allowed to modify any of its objects.
member.
Unfortunately, many members of the Bitwise Constness definition can also be tested through Bitwise. special
Don't, a member function of "Data" pointed to by the pointer ", its behavior clearly violates Bitwise Cons
Tness definition, but if only this pointer is included in the object, this function is also bitwise const, compile time
by. This is different from our intuition:
Class string {
PUBLIC:
// Construct the function to point Data points to one
// Value Points to Data Copy
String (const char * value);
...
Operator char * () const {return data;}
Private:
CHAR * DATA;
}
const string s = "hello"; // Declaration constant object
Char * Nasty = S; // Call Operator Char * () Const
* Nasty = 'm'; // Modify S.Data [0]
Cout << S; // Output "Mello"
Obviously, what is wrong with a constant object with a value and call the object's Const member function,
The value of the image can be modified! (About this example is discussed in more detail in detail 29)
This results in the introduction of the Conceptual Constness view. The persistence of this point of view, believes that a constant function
You can modify some of the data (BITS) of the object, but only if the user will not be found. For example, fake
Setting the String class wants to save the object length each time the request is requested:
Class string {
PUBLIC:
// Construct the function to point Data points to one
// Value Points to Data Copy
String (const char * value): LengthsValid (false) {...}
...
SIZE_T longth () const;
Private:
CHAR * DATA;
SIZE_T DATALENGTH; / / Finally calculated / string length
Bool Lengthsvalid; // Currently
// is it legal
}
SIZE_T STRING :: Length () const
{
IF (! lengthisvalid) {
DATALENGTH = Strlen (data); // Error!
Lengthsvalid = true; // Error!
}
Return Datalength;
}
This Length's implementation is clearly not in line with the definition of "Bitwise Const" - Datalength and LengthsVA
LID can be modified - but for Const String objects, it seems to be legitimate. But compiler
Do not agree, they insist on "Bitwise Constness", what should I do?
Solution is simple: use the C Standard organization to specifically provide the Const Problem for this situation.
Option. This scheme uses keyword Mutable when using Mutable for non-static data members, these members
"Bitwise Constness" is restricted:
Class string {
PUBLIC:
... // Same as Above
Private:
CHAR * DATA;
Mutable size_t datalength; // These data members are now
/ / For mutable; they can
Mutable Bool LengthsValid; // Announced anywhere, even
// In Const member functions
}
SIZE_T STRING :: Length () const
{
IF (! lengthisvalid) {
Datalength = Strlen (data); // Now legal
Lengthsvalid = true; //
}
Return Datalength;
}
Mutable is a good solution when processing the "Bitwise-Constness" problem, but it is added to C
The time in the standard is not long, so some compilers may not support it. If so, you have to go back to C.
Dark old era goes, there, life is very simple, constant may sometimes be abandoned.
Among a member function of class C, the pointer is as follows:
C * const this; // Nonconst member functions
Const C * const this; // Const member function
In this case (ie, the compiler does not support Mutable), if you want to make the problem String :: Len
The GTH version is legal for Const and non-Const objects, only change the THIS type from Const C * Const to C
* const. Can't do it directly, but you can initialize a local variable pointer to make it point to this.
The same object is indirectly implemented. Then, you can access the members you want to modify through this partial pointer:
SIZE_T STRING :: Length () const
{
/ / Define a way not pointing to the Const object
// Local version of this pointer
String * const logalthis =
Const_cast
IF (! lengthisvalid) {
Localthis-> datalength = strlen (data); LOCALTHIS-> longthisvalid = true;
}
Return Datalength;
}
Don't be very beautiful. But in order to complete the desired function, only do it.
Of course, if this method cannot be guaranteed, don't do this: For example, some old "elimination const"
The method is not. In particular, if the object referred to this is really const, that is, it is declared as constation when defined.
ST, then "eliminating const" will result in unsureable consequences. So, if you want to pass through the member function
To change Const, it is best to first be confident that the object you want to convert is not defined as const.
In other cases, the CONST will be both useful and safe through the type conversion. This is: put a const object
Pass to a function that takes a non-const parameter, and you know that the parameters will not be modified inside the function.
. The second condition is very important, because the object that is only read (will not be written) eliminating constant is always safe.
Even if that object is initially defined as const.
For example, I already know that some libraries do not correctly declare the Strlen functions below:
SIZE_T STRLEN (CHAR * S);
Strlen, of course, will not modify the data referred to S - at least I have never seen it in a lifetime. But because of this statement,
When calling this function when calling this function for a const char * type, it will be illegal. To solve this problem, you can
Convert this pointer's const forces to Strlen to Strlen:
Const char * klingongreeting = "nuqneh"; // "nuqneh" "Hello"
//
SIZE_T Length =
Strlen (const_cast
But don't abuse this method. Only in the called function (such as Strlen in this example) does not modify its parameters
When the data is referred to, it can guarantee that it can work normally.
-