Operator overload Manual

Source: Internet
Author: User
I. Heavy Load rules

I. Operators that can be overloaded

+ - * / %
^ & | ~ !
= > < + = -=
* = /= % = ^ = & =
| = > < >>= <=
= ! = > = <= &&
| ++ -- -> * ,
-> [] () Operator new Operator new []
Operator Delete Operator Delete []

Ii. Operators that cannot be overloaded

:: . .* ? :
Sizeof Typeid New Delete
Static_cast Dynamic_cast Const_cast Reinterpret_cast

III. Basic Rules

1. The unary operator can be a member function without Parameters[1]Or a non-member function with a parameter[1].
2. Binary operators can be member functions with a parameter[1]Or non-member functions with two parameters[1].
3. Operator =, operator [], operator (), operator-> can only be defined as a member function[1].
4. the return value of operator-> must be a pointer or an object that can use->.
5. When operator ++ and operator are reloaded, an int parameter is included to indicate the suffix, and no parameter is included to indicate the prefix.
6. Except operator new and operator Delete, at least one non-built-in data type must be included in the overloaded operator parameters.
7. x @ Y the search range is: x member functions --> Functions in global functions/functions in the namespace where X is located/functions in the namespace where Y is located/Friends of X
Number/y.
8. The overloaded operators should try to simulate the behavior of the operators to build types internally.

Ii. Some suggestions on using the overload I. Operator overload

1. only the operator (such as: + =) that will change the value of the first parameter is defined as a member function, and the operator (such as: +) of a new object will be returned) it is defined as a non-member function (and implemented using ++ = ).
2. Only non-member functions can implement gender conversion on the left parameter. If conversion is required, the operator should be defined as a non-member function.
3. For the unary operator, it is best to overload it as a member function to avoid implicit conversion.
4. For binary operators, in order to be able to perform the same implicit conversion as the right operand on the left operand, it is best to overload them as non-member functions.
5. Operator >>and operator <<should be defined as non-member functions to comply with the usage habits.
6. If operators such as operator [] are reloaded, the const version and non-const version should be provided as much as possible.
7. For the definition of operators as members or non-members, refer to the following suggestions:

Operator Suggestions
All unary Operators   Member
= () []->   Must be a member
+ =-=/= * = ^ = & =! ==>>=<<=   Member
Other binary Operators   Non-member

8. If the default operator can already be applied to your type, avoid overloading the operator, such as operator, operator & (get address), and so on.

Ii. Heavy Load operator new

1. Why reload operator new?

[Efficiency problem] The system usually provides a very slow distributor speed by default, and the waste of allocating small objects is serious.
[Change behavior] if the default distributor fails, an exception is thrown. You may want to change this behavior.

2. Operator new action

[Differentiate three different New]
New operator (new expression, new operator, new expression): This operator is usually used when we call X * PX = new X. It is built in the language and cannot be overloaded, it cannot change its behavior. it includes operator New for memory allocation and placement New for calling constructors.
Operator New: opeator new is a function, void * operator new (size_t size ). it allocates memory of the specified size and can be overloaded. You can add additional parameters, but the first parameter must be size_t. in addition to being called by new operator, operator new can also be called directly: void * rawmem = Operator new (sizeof (x )).
Placement New: Placement new uses constructor on a specified memory, including the header file <New>. You can also directly use placement New: x * PX = new (rawmem) X. [2]

Similar to new operator, for Delete operator, operator Delete: void operator Delete (void *) also exists. The Destructor PX-> ~ X ().

[Operator new error handling]
The default operator new will throw the STD: bad_alloc exception when memory allocation fails; nothrow new[3]
(X * PX = new (nothrow) x) 0 is returned when memory allocation fails. this behavior can be changed by setting new-handler. new-handler is a callback function pointer, typedef void (* new_handler) (void ). after the callback handle is set through the set_new_handler (new_handler) function, if the memory allocation fails, operator new will continuously call the new-handler function until enough memory is found. to avoid endless loops, the new-handler function must have one of the following actions:
(1). Find available memory.
(2) install other new-handler functions.
(3). Remove New-handler, that is, set_new_hanlder (0). In this way, the default action will be resumed in this loop, and an exception will be thrown or 0 will be returned.
(4). Throw an exception.
(5) Save the error log and exit the program.

3. Prepare to reload operator new

When operator new is reloaded, it must be compatible with the default operator new error handling method. in addition, C ++ Standard specifies that a valid memory address should be returned when the required memory is 0 bytes. therefore, the implementation of operator new overload should be as follows: void *... operator new (size_t size ...)
{
If (size = 0)
Size = 1;

While (1)
{
... // Allocate memery
If (allocate sucessfull)
Return... // return the pointer.

New_handler curhandler = set_new_handler (0 );
Set_new_handler (curhandler); // get current new handler

If (curhandler = 0)
(* Curhandler )();
Else
Throw STD: bad_alloc ();
}
}

Reload operator Delete is much simpler. You only need to note that C ++ standard requires that deleting a null value is safe.

4. Reload operator new

The overload of opeator new is very different from that of other operators. first, the default operator new can be applied to your custom type, even if you do not reload it. second, when other operators are overloaded, the number of parameters is fixed, while the number of operator new parameters can be arbitrary. You only need to ensure that the first parameter is size_t and the return type is void, in addition, the overloaded parameter types do not need to include custom types. more generally, Operator new is more like a function overload than an operator overload.

[★Reload operator new with different parameters]

Operator new can be reloaded by using different parameter types, for example:

Void * operator new (size_t size, int X, int y, int Z)
{
...
}

X * PX = new (1, 2, 3) X;

You can also use the default value for operator new overloading. The principle is the same as that for normal function overloading, as long as there is no conflict with the existing form. you may have thought that you can even use the variable parameter in operator new, if you really need it.

Void * operator new (size_t size, int X, int y = 0, int z = 0)
{
...
}

X * PX = new (10) X;
Y * py = new (10, 10) y;
Z * PZ = new (10, 10, 10) Z;

...
Void * operator new (size_t size ,...)
...

You can also directly reload the void * operator new (size_t size) function in the global space. This will change the behavior of all default new operators and is not recommended.

[★Reload the class's exclusive operator New]

When operator new is overloaded for a class, it must be defined as a static function of the class.[4]Because operator new will be called before the class object is constructed. that is to say, when operator new is called, this pointer does not exist, so the overloaded operator new must be static. of course, you can add additional parameters and use the default value to overload operator new in the class. in addition, like normal functions, operator new can also be inherited.

Class X {
...
Static void * operator new (size_t size); //... (1)
Static void * operator new (size_t size, INT); //... (2)
};

Class Y: Public X {
...
};

Class Z: Public X {
...
Static void * operator new (size_t size); //... (3)
};

X * px1 = new x; // call (1)
X * px2 =: New X; // call default operator new
X * px3 = new (0) x; // call (2)

Y * py1 = New Y; // call (1)

Z * pz1 = new Z; // call (3)
Z * PZ2 =: new Z; // call default operator new
Z * pz3 = x: new Z; // error, no way to call (1)
Z * pz4 = new (0) Z; // error, no way to call (2)

5. Reload operator Delete

If you reload an operator new, remember to reload the operator Delete in the same range. because only you can know how to release the allocated memory. if you forget it, the compiler will not prompt you, And it will use the default operator Delete to release the memory. the cost of this kind of forgetting is heavy. You have to write operator delete while writing operator new.
If operator Delete is used in the class, it must also be declared as a static function, because when operator Delete is called, the object has been destructed. Operator Delete overload can be in two forms:
(1) void operator Delete (void * MEm)
(2) void operator Delete (void * MEM, size_t size)
In addition, operator Delete can both exist. When Delete PX is called, if expression (1) exists, operator Delete (1) is called. the (2) type is called only when the (1) type does not exist. for operator Delete in the form of (2), if the base class pointer is used to delete the derived class object, and the base class destructor is not virtualized, the size value may be incorrect.

Iii. Heavy Load reference show all

+ Const carrot operator + (const carrot & LHS, const carrot & RHs)

{
Carrot result = LHS;
Return result + = RHS;
} [Note] 1. If possible, use operator + = to implement operator +.
2. Operator + cannot return references. The type of return value should be.
3. To prevent calls such as (A + B) = C, the return value should be declared as Const.

· Const carrot operator-(const carrot & LHS, const carrot & RHs)
+ Const carrot operator * (const carrot & LHS, const carrot & RHs)

{
...
} [Note] 1. Operator * can also be overloaded as the pick-up operator.

· Const carrot operator/(const carrot & LHS, const carrot & RHs)
· Const carrot operator % (const carrot & LHS, const carrot & RHs)
· Const carrot operator ^ (const carrot & LHS, const carrot & RHs)
+ Const carrot operator & (const carrot & LHS, const carrot & RHs)

{
...
} [Note] 1. Operator & can also be reloaded as the address fetch operator.

· Const carrot operator | (const carrot & LHS, const carrot & RHs)
+ Const carrot: Operator-() const

{
Carrot result = (* This );
... // Chang the value to negative
Return result;
} [Note] 1. unary operator, negative.

· Const carrot: Operator ~ () Const
· Bool carrot: Operator! () Const
· Bool operator> (const carrot & LHS, const carrot & RHs)
· Bool operator <(const carrot & LHS, const carrot & RHs)
+ Carrot & carrot: Operator = (const carrot & RHs)

{
If (this = & RHs)
Return * This; // may be (* This) = RHS if needs.

Barley: Operator = (RHs); // If carrot DERIVED FROM BARLEY

... // Assignments every memeber of carrot.

Return * this;
} [Note] 1. In order to realize the concatenation assignment operation in the form of X = y = z = 0, operator = must return a non-constant reference of * This.
2. When assigning values, check whether the value is self-assigned (A = ).

+ Carrot & carrot: Operator + = (const carrot & RHs)

{
...
Return * this;
} [Note] 1. c ++ allows a value assignment (x + = 1) = 0. Operator + = must return a very large reference of * This.

· Carrot & carrot: Operator-= (const carrot & RHs)
· Carrot & carrot: Operator * = (const carrot & RHs)
· Carrot & carrot: Operator/= (const carrot & RHs)
· Carrot & carrot: Operator % = (const carrot & RHs)
· Carrot & carrot: operator ^ = (const carrot & RHs)
· Carrot & carrot: Operator & = (const carrot & RHs)
· Carrot & carrot: Operator | = (const carrot & RHs)
+ Istream & operator> (istream & _ istr, carrot & RHs)

{
...
Return _ istr;
} [Note] 1. In order to comply with the use habits (CIN> X instead of x> CIN), the operator> of the convection operation should be a non-member function.

+ Ostream & operator <(ostream & _ ostr, const carrot & RHs)

{
...
Return _ ostr;
}

+ Const carrot operator> (const carrot & LHS, int RHs)

{
Carrot result = LHS;
...
Return result;
} [Note] 1. Method of overloading the shift operation.

· Const carrot operator <(const carrot & LHS, int RHs)
+ Carrot & carrot: Operator >>=( int RHs)

{
...
Return * this;
} [Note] 1. shift operation.

· Carrot & carrot: Operator <= (INT RHs)
+ Bool operator = (const carrot & LHS, const carrot & RHs)

{
...
}

· Bool Operator! = (Const carrot & LHS, const carrot & RHs)
· Bool operator> = (const carrot & LHS, const carrot & RHs)
· Bool operator <= (const carrot & LHS, const carrot & RHs)
+ Bool operator & (const carrot & LHS, const carrot & RHs) x

{
...
} [Note] 1. You should avoid overloading operator & and operator for the following reasons |:
(1). & | is a logical operator. It has a clear semantics only for the bool type.
(2). overloaded operator & and operator | the default sticky semantics of operators cannot be simulated. [5].
(3). You cannot guarantee the order of the parameters of the operator after the overload (C ++ stand ensures the default & and | left to right ).
2. The custom type can be considered to provide bool transformation operations to support this operator.

· Bool operator | (const carrot & LHS, const carrot & RHs) x
+ Carrot & carrot: Operator ++ ()

{
(* This) + = 1; // or other implement
Return * this;
} [Note] 1. Prefix: ++ carrot

+ Const carrot: Operator ++ (INT)

{
Carrot oldvalue = * this;
++ (* This );
Return oldvalue;
} [Note] 1. Postfix: when calling carrot ++, the compiler automatically generates a 0 value as the parameter.
2. to disable the carrot ++ operation, the return value should be const.
3. From the implementation and parameters, we can see that the efficiency of the post-operation is much lower than that of the pre-operation. Therefore, you should try to use the pre-operation unless necessary.
4. To ensure consistency of incremental behaviors and facilitate maintenance of post operations, it is best to use pre-operations to complete incremental behaviors.

· Carrot & carrot: Operator --()
· Const carrot: Operator -- (INT)
+ Const carrot operator, (const carrot & LHS, const carrot & RHs) x

{
...
} [Note] 1. You should avoid overloading operator for the following reasons ,:
(1). Even if there is no overload, the default number operator can also be applied to custom types.
(2) c ++ guarantees that the operator is evaluated from left to right, but this behavior cannot be guaranteed after heavy load.

+ Const pmfc Carrot: Operator-> * (returntype (T: * PMF) () const

{
...
} [Note] 1. Operator-> * heavy load is rare. For more information, see implementing operator-> * for smart pointers.

+ Const carrot * carrot: Operator & () const x

{
...
} [Note] 1. You should try to avoid overloading the address operator.

+ Coca & carrot: Operator *()

{
...
} [Note] 1. The overloaded pick-up operator should provide the const version and non-const version.

· Const coca & carrot: Operator * () const
+ Coca * carrot: Operator-> ()

{
...
} [Note] 1. heavy-load operator-> const and non-const versions should be provided.
2. the return value of operator-> must be a pointer or can be applied-> operation type.
3. If operator-> does not return a pointer, C ++ will continue to apply it to the return type-> until a pointer is obtained.

· Const coca * carrot: Operator-> () const
+ Coca & carrot: operator [] (keytype index)

{
...
} [Note] 1. OPERATOR [] shall provide the const version and non-const version.
2. The keytype can be of any type, but it is usually of the int type.

· Const coca & carrot: operator [] (keytype index) const
+ Anytype carrot: Operator ()(...)

{
...
} [Note] 1. Operator () is overloaded with function operators. () that changes the expression priority cannot be reloaded.
2. objects that have been overloaded with operator () are converted into function imitation functions. The usage method is similar to that of function pointers.

+ Static void * carrot: Operator new (size_t size ,...)

{
If (size = 0)
Size = 1;

While (1)
{
... // Allocate memery
If (allocate sucessfull)
Return... // return the pointer.

New_handler curhandler = set_new_handler (0 );
Set_new_handler (curhandler); // get current new handler

If (curhandler = 0)
(* Curhandler )();
Else
Throw STD: bad_alloc ();
} [Note] 1. Refer to reload operator new.

· Static void * carrot: Operator new [] (size_t size ,...)
+ Static void carrot: Operator Delete (void * Memory, size_t size)

{
If (memorty = NULL)
Return;
...
} [Note] 1. Refer to reload operator new.

· Static void carrot: Operator Delete [] (void * momery, size_t size)

Note: 1. In this article, member functions only refer to non-static member functions. Non-member functions include free functions, static member functions, and friend functions. Limit 2. this call method uses an overloaded form of operator New: void * operator new (size_t, void * buff ). this overload method directly returns the input memory address, so operator new in this call method actually does nothing, so thisNew operatorThe call only uses the part where the constructor is called, which is equivalent to calling placement new. This overload is in vc7.1. # DEFINE _ placement_new_inline
Inline void * _ cdecl operator new (size_t, void * _ Where) _ throw0 ()
{// Construct array with placement at _ Where
Return (_ Where );
}

3. Like placement new, nothrow new is also an overloaded form of operator new. nothrow is An object declared in. This overload is in vc7.1 The declaration in is :...
Struct nothrow_t
{// Placement new tag type to suppress exceptions
};

Extern const nothrow_t nothrow; // constant for placement new tag
...
Void * _ cdecl operator new (size_t, const STD: nothrow_t &)
_ Throw0 ();

Lifecycle 4. in vc7.1, compiling can still be performed without declaring operator new as a static function. However, if a non-static member is used in the function, a compilation error occurs. it can be seen that even if operator new is not declared as a static function, the compiler will treat it as a static function. even if the compiler treats operator new as a static function by default, it should be explicitly declared as a static function. bytes
5. that is, if the left operand of the & operator is false, false is directly returned without detecting the right operand. | if the left operand of the operator is true, returns true without detecting the value of the right operand. so code like this can be safe:
If (P! = NULL) & strlen (p) <10 )...
If P = NULL, strlen will not be called. but the overloaded operator & and operator | is used as a function. This operator is called only after all the parameter values are evaluated. bytes

▲References:

1. Bjarne stroustrup. The C ++ programming language (Special Edition)
2. Scott Meyers. Valid tive C ++ (2nd edition)
3. Andrei Alexandrescu. Modern C ++ Design
4. Robert B. Murray. c ++ strategies and tactics
5. Scott Meyers. More effective tive C ++
6. John lakos. Large-scale C ++ Software Design
7. Scott Meyers. Implementing operator-> * for smart pointers

Reference: http://www.adintr.com/program/article/05.oper.html#mu1f

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.