Gotw # 04 Class Mechanics
Author: Herb Sutter
Translation: Kingofark
[Declaration]: This article takes the Guru of The Week column on www.gotw.ca website, and its copyright belongs to the original person. Translator Kingofark translated this article without the consent of the original person. This translation is only for self-study and reference, please read this article, do not reprint, spread this translation; people download this translation content, please delete its backup immediately after reading. Translator Kingofark is not responsible for people who violate the above two principles. This declaration.
Revision 1.0
GURU Of The Week Terms 04: Techniques for Class
Difficulty: 7.5 / 10
(Do you have multiple lines in implementing the details of the class? This Terms must not only tell some terrible mistakes, but also more about professional coding style.)
[problem]
You are examining a class prepared by another programmer (see below), this class is very bad, and there are still some serious errors. How many people can you find, how to modify it?
Class complex {
PUBLIC:
Complex (Double Real, Double Imaginary = 0)
: _Real (real), _imaginary (imaginary) {};
Void OPERATOR (Complex Other) {
_real = _Real other._real;
_imaginary = _imaginary other._imaginary;
}
Void Operator << (Ostream OS) {
OS << "(" << _Real << "," << _imaginary << ")"
}
Complex Operator () {
_R;
RETURN * THIS;
}
Complex Operator (int) {
Complex Temp = * this;
_R;
Return Temp;
}
Private:
Double _Real, _imaginary;
}
[answer]
[Foreword]: In fact, this class is more than what we have to tell below. But the intention of this problem, it is said that it is to point out the interface that is very poor design, it is better to say that it is mainly to reflect the construction techniques of the class (such as "typical Operator << how is it realized?", " Do Operator as a member? ", Etc.). No matter what to say, I will start from the very useful 0 point ...
0. Since there is a COMPLEX class in the standard library, why bother to write one? (More Over Overthable Standard Library is the best master's experience in the industry's most experienced experience, there is absolutely no problem with the following story. So, you still "Not" Notice "!)
[Learning Guidance]: Please read the algorithm of the standard library, not to write its own algorithm version. This is faster, it's easier, safer!
* Class Complex {
PUBLIC:
Complex (Double Real, Double Imaginary = 0)
: _REAL (REAL), _IMaginary (imaginary) {}; 1. Style Description: This can be used as a constructor of a single parameter, including an implicit conversion operation. But attention, don't always do this!
[Learning Guidance]: Never pay attention to those "quiet" conversion operations. A good way to avoid it is to explicitly use the use constructor (constructor) as possible.
* Void OPERATOR (Complex Other) {
_real = _Real other._real;
_imaginary = _imaginary other._imaginary;
}
2. Style Description: For efficiency, its parameters should be const &; and, the statement like "a = a b" should be rewritten into "A = B".
[Rules]: Please pass Const &, not to pass the copy.
[Learning Guidance]: For arithmetic operations, use "A OP = B" in the form of "a = a OP B" (of course, in some classes - you should never write this kind Let's! (Sweat) - OP and OP = are not the original equivalent relationship. This situation is except.).
3. Style Description: Operator should not be considered as a member function. If it is a member function like the above code, you can only write "A = B 1", and must not write "a = 1 b". For efficiency, you may also want to provide Operator (int) (int, complex).
[Learning Guidance]: For a member of a member, it is a non-member function, follow the rules mentioned in (Lakos96: 143-144; 591-595; murray93: 47-49), ie
l One yuan operator is a member function
l =, (), [] and -> must be a member function
L =, - =, / =, * = (etc.) is a member function
l All other binary operators are non-member functions
4. Error Description: Operator should not change the value of this object, and a temporary object containing addresses should be returned. Note that in order to avoid use like "A B = C", the return type should be const complex (not Complex).
(In fact, this part of the code is closer to the implementation of Operator =, not the Operator implementation.)
5. Style Description: In general, if you define OP, then you should also define OP =. As far as the code given here, because you define Operator , you should also define Operator =. As a result, the above function should be the implementation of Operator =, either the return value is screwed, see the following description). * Void Operator << (Ostream OS) {
OS << "(" << _Real << "," << _imaginary << ")"
}
(Author: For an authentic Operator <<, you should also consider doing some extra things, such as checking the current formatted flag (Format Flag) to make it conform to usa. You can check your most Good STL books for more detailed description. Recommended here: Steve Teale's "C iostreams Handbook", Glass and Schuchert's "The STL
6. Error Description: Operator << Should not be a member function (see the rules above); and the parameters should be (Ostream &, Const Complex &). Pay attention here, as James Kanze said, do not let it become a friend! Correspondingly, the problem can be solved by calling a public member function print.
7. Error Description: The return type of the function should be Ostream &; and the function should end with the "return OS;" statement, allowing a chain expression (ie, you can write "cout << a << b;" said statement ).
[Rules]: Always let Operator << and Operator >> Street Reference.
* Complex Operator () {
_R;
RETURN * THIS;
}
8. Style Description: Preincrement operation should return Complex &, allowing the code to call it to be more intuitive.
* Complex Operator (int) {
Complex Temp = * this;
_R;
Return Temp;
}
9. Style Description: PostIncrement action should return Const Complex. This avoids the strange statements like A beyond a coding novice.
10. Style Description: Implement the postIncrement operation in accordance with the preware of the preincent operation.
[Learning Guidance]: Please implement the postIncrement operation according to the mode of the preincray operation. * Private:
Double _Real, _imaginary;
}
11. Style Description: Try to avoid using the name of the following scribe. Yes, I am always used to use them; good, some popular books like "Design Patterns" (Gamma et al) also use them. But on the one hand, the C standard retains some of the following marking of the following scribes for some implementation; on the other hand, whether it is for you or for the compiler, you have to remember that the relevant rules are very difficult. So, you'd better avoid using the name of the following scribe lines in your own code. (In view of the fact that I have been banned from the beginning of my own member variable, I now use the way the following scribe is ended as an alternative!)
All right. Now I finally got the correct code version of this program, here we ignore the problem of designed and coding styles that have not been mentioned above:
Class complex {
PUBLIC:
Explicit Complex (Double Real, Double Imaginary = 0)
: Real_ (real), imaginary_ (imaginary) {}
Complex & Operator = (const complex& "{
REAL_ = Other.Real_;
Imaginary_ = Other.imaginary_;
RETURN * THIS;
}
Complex & Operator () {
real_;
RETURN * THIS;
}
Const Complex Operator (INT) {
Complex Temp = * this;
(* this);
Return Temp;
}
Ostream & Print (Ostream & OS) Const {
Return OS << "(" << REAL_
<< "," << iMaginary_ << ")";
}
Private:
Double Real_, imaginary_;
Friend Ostream &
Operator << (Ostream & OS, Const Complex & C);
}
Const Complex Operator (Const Complex & LHS,
Const complex & rhs) {
Complex Ret (LHS);
RET = RHS;
Return Ret;
}
Ostream & Operator << (Ostream & OS,
Const Complex & C) {
Return C.Print (OS);
}