Needless to say, this is about Operator overload. About operator, the description in < the C + + programing Language > can be used as a overload as follows:
+ */% ^ & | ~ ! = < > + = *=/=%= ^= &= |= << >> >>= <<= = = = <=
>= && | | + + >*, > [] () new new[] Delete delete[]
Start with operator = speak first. Aear already mentioned in the previous chapter, here again, as long as there is pointer in class member, class should provide copy constructor and operator =.
In addition to operator =, the most commonly used operator is +-*/+ =-+ *=/= + +--。 As the arithmetic is very similar, we take simple + to give examples. Let's take a look at what's wrong with this piece of code:
Class Test {
Private
int internaldata;
Public
Constructor and destructor
Test (int data = 0): Internaldata (data) {};
Test (const Test & Para): Internaldata (Para.internaldata) {};
~test () {};
Operator overlording
Test & operator + = (const Test & PARA1);
Test operator + (const test & PARA1);
};
Test & Test::operator + = (const Test & PARA1)
{
Internaldata + = Para1.internaldata;
return * this;
}
Test Test::operator + (const Test & PARA1)
{
Test result;
Result.internaldata = Internaldata + para1.internaldata;
return result;
}
First let's compare the efficiency of + = and + two operator, we can see that in "+ =", the return is *this reference, and in +, the return is a temporary creation of the result, and the result object in the process of return, Because it is return by value, the compiler will drop the copy constructor to the return value and then destroy the temporary variable with result.~test (). In other words, use + + + to produce more overhead. In the case of some efficiency first, the constructor and destructor of temporary variables are very expensive operations. Like what:
=============one Temporary object=============
Test x1 = x2 + x3;
To improve efficiency, we can write:
=============no Temporary object=============
Test X1 (x2);
x1 + = x3;
Simple expressions may be optimized by compiler, but complex expressions can only be optimized in manual form.
Let's take a closer look at the function of Test Test::operator + (const Test & PARA1). If we consider the specific implementation of the program, we can see that operator + = and operator + have no intrinsic but not, but if we need to change the operation of Test +, it must be changed at the same time operator + = AND operator + implementation, the same function in several different Local maintenance is not a good design, so we should make the following changes to Test Test::operator + (const Test & PARA1) to make the program easier to maintain:
=============easy to maintain=============
Test Test::operator + (const Test & PARA1)
{
Test result (*this);
result + = PARA1;
return result;
}
You can see that the + = operation is called in operator +, so if we need to give the addition a different meaning, we just need to change operator + = to be sufficient.
Let's continue in-depth look at Test test::operator + (const Test & PARA1). It is worth emphasizing that, in any case temporary object is a must exist, the experience of countless masters, want to use static member, dynamic memory and other methods to eliminate temporary object construction and Destruction, there are logical and procedural errors that can occur.
But we can still use compiler to optimize this temporary object. For operations such as test Test::operator + (const Test & Para1), compiler is passed to operator + a temporary object, if the code in the operator + is appropriate, then Compiler will use this temporary object instead of the temporary object created in the program, thus reducing the loss of constructor and destructor. The pseudocode after compiler optimization are as follows:
Test::operator + (Test & temporary, const Test & PARA1)
{
Temporary.internaldata = Internaldata + para1.internaldata;
Return
}
This reduces the construction and destruction of the temporary object, which can be much more efficient, but to enable compiler to optimize for return by value, 2 conditions must be met:
1. Class must have copy constructor
2. In the code, it is clear that the return is a temporary object.
Therefore, in addition to the provision of copy constructor, you must also make appropriate modifications to operator +, the final code is as follows:
==========final Version for maintenance and optimization==========
Test Test::operator + (const Test & PARA1)
{
Return Test (*this) + = PARA1;
}
In this code, the most obvious difference is that without the result of the variable, instead of returning a temporary created test object, compiler will know that this function can be optimized with temporary variables.
You may be surprised, but this operator + is not the quickest. Because we see, in the process of test (*this) + = Para1, call a constructor once operator + =, but enough. But for the sake of efficiency, we have more extreme methods, in the following code, we discard the readability, maintainability, and so on, only for faster speed:
========== a bad style, but faster ==========
Class Test {
...
Private
Cosntructor for operator +
Test (int data, const Test & Para1): Internaldata (data + para1.internaldata) {};
};
Test Test::operator + (const Test & PARA1)
{
Return Test (Internaldata, PARA1);
}
If you also define the constructor of the operator-*/And other operations, we can change the signature of the constructor appropriately so that different operations can be implemented with constructor
About operator The first part of today said so much, we have time to sit http://blog.sina.com.cn/u/1261532101 ; see you.
======================================================
Please refer to my article for reference, more details please refer to the authoritative books
<c++ Programming Language> If there are errors and omissions in the text,
Please note that Aear will try to correct, thank you!
======================================================
To continue with the previous chapter, the following is the adjusted test class code:
Class Test {
Private
int internaldata;
Public
Constructor and destructor
Test (int data = 0): Internaldata (data) {};
Test (const Test & Para): Internaldata (Para.internaldata) {};
~test () {};
Operator overlording
Test & operator + = (const Test & PARA1);
Test operator + (const test & PARA1);
};
Test & Test::operator + = (const Test & PARA1)
{
Internaldata + = Para1.internaldata;
return * this;
}
Test Test::operator + (const Test & PARA1)
{
Return Test (*this) + = PARA1;
}
Let's say we want to add a new function to the test class so that the test class and integer can be added. This means that you can execute the following code:
Test X1 (10);
X1 = x1 + 5;
X1 + = 5;
In fact, we do not need to make any changes, the above code will be able to execute correctly. Because the constructor we provide Test (int data = 0) can be implicitly (implicit type conversion) convert an integer to a temporary test Object, and then drop the test Test::opera Tor + (const Test & PARA1). Therefore, the above code is equivalent to:
X1 = X1.operator + (Test (5));
X1 = x1.operator + = (Test (5));
Implicit Type Conversion actually brings a lot of trouble, to avoid the potential danger, it is best to precede the test (int data = 0) with explicit, indicating that if the Interger is converted to test, it must be controlled by the programmer, compiler do not perform covert operations. So, to be like X1 = x1 + 5 can work, there are 2 ways:
X1 = x1 + static_cast<test> (5);
Or
X1 = x1 + Test (5);
It is also important to note that if you do not use explicit type conversion, you can run:
X1 = x1 + 5;
But in compiling:
X1 = 5 + x1
, unless you use a temporary Object, such as:
X1 = Test (5) + x1;
The best way to enable test Class to support x1 = 5 + x1 is to use helper function. Let's look at another way to define operator.
================== Split Line ==================
We can use friend function to define the addition operation of the Test Class, which is the following code:
Class Test {
Test (int data = 0): Internaldata (data) {};
...
For this test Class, the following line is not required.
Friend Test operator + (const TEST & PARA1, const Test & PARA2);
};
Test operator + (const TEST & PARA1, const Test & PARA2)
{
Return Test (Para1) + = Para2;
}
The first thing we need to note is that Test (int data = 0) is not explicit, which means that implicit type conversions can be performed, so either run:
X1 = x1 + 5;
Still is:
X1 = 5 + x1;
are able to compile and pass.
Solve the basic functional problems, let's continue to consider the efficiency. Whether it's X1 = x1 + 5, or x1 = 5 + x1, it's not necessary to lose at least the extra constructor and destructor to convert 5 to test Object. Second, allowing compiler to implicit type conversion is not a good habit. The solution to these problems is to provide a dedicated operator + to perform an addition operation between the integer and test object, as follows:
========== Support X1 + 5 ==========
Test operator + (const TEST & Para1, int Para2)
{
Return Test (Para2) + = PARA1;
}
========== Support 5 + x1 ==========
Test operator + (int Para1, const Test & PARA2)
{
Return Test (Para1) + = Para2;
}
Also add the following 2 lines to the class test (not required for this example, but normally required):
Friend Test operator + (int Para1, const Test & PARA1);
Friend Test operator + (const TEST & Para1, int Para2);
and add explicit to the front of the constructor. Of course, you can also use the template to define, as follows:
========== Support X1 + 5 ==========
Template <class t>
T operator + (const T & Para1, int Para2)
{
Return T (Para2) + = PARA1;
}
In fact, I personally do not recommend the definition of template. The first is because of the namespace problem, in the end is global namespace it? Or is it a local namespace? In the case of global namespace, not all global classes need operator +, which provides extra class operations. Local namespace can be used, provided that all classes define + =. Perhaps for most classes, the operator + operation is not required. So I think the definition of operator, try to use less template (personal view).
================== Split Line ==================
Let's talk about the operator of type conversions. For an abstract Data type, the type conversion is often used, such as the one we mentioned earlier to convert from integer to Test, you can use implicit type conversion and explicit type conversion. But if we want to convert from test to Integer,compiler, we can't support automatic type conversions, so we need to provide the appropriate operator:
Class Test {
...
Type converstion from Test to int
operator Int () {return internaldata;};
}
Then we can do it:
int i = Test (10);
In fact, operator INT () is also a implicit type conversion, which is controlled by the programmer. Good program design, is the programmer can precisely control every small operation. Therefore, it is not recommended to use operator int (), a good approach is to provide a asint () method, as given in < effective C + + >, to do explicti type conversion:
============ Explicti ============
Class Test {
...
Type converstion from Test to int
int Asint () {return internaldata;};
}
================== test++ & ++test ==================
I believe everyone knows what the difference between Prefix + + and Postfix + + is, and here's the code:
Prefix
test& operator++ ()
{
++internaldata;
return (*this);
}
Postfix
Test operator++ (int)
{
++*this;
Return--test (*this); In order to use the return value optimization, you need to define--test
}
We simply look at the efficiency problem, in prefix that is, + + is returned by the reference, no temporary object, returned in the Postfix is an object, using the temporary. I believe we all know, can not use test++ place do not use, try to use ++test.
Like what:
for (Iterator i = XXX; XXX; ++i)//Do not use i++
For postfix, compiler is not guaranteed to be optimized to prefix, so try to be careful when writing code.
================== Other about operator ==================
Some operator are not recommended for overload, as unforeseen circumstances can occur. These operator include:
&&, | | , &, | , ","
For a simple example, if you overload "," then there is a for loop as follows:
for (Test x1 = x2,i = 0;;) {....}
What is X1 = x2 and i = 0? or X1 = X2.operator, (i) = 0? If overload &, for logical judgment, X1 && x2, is x1 && x2? or X1.operator & (&X2)? So these overload will produce a lot of puzzling questions.
Secondly, many operator overload need to be treated with care, these operator are as follows:
New new[] Delete delete[], [] ()
Please read the C + + standard carefully, understand the details, and then overload these operator, otherwise it is easy to cause the instability of the program.
operator of C + + basic Skills