Operator overloading is one of the most important language features of C + +. This article will use code examples to answer--c++ which operators can overload? How to reload? What do I need to pay attention to when implementing operator overloading?
Which operators can be overloaded and which cannot be overloaded?
C++98,C++0X,C++11 has a consistent provision for "which operator overloads can be overloaded." Details such as the following:
Very few of them use the "," (comma operator).
The same standard specifies the non-overloaded operators :
, "::" is the scope operator.
"?:" is the conditional operator.
The two less-used operators are. * and->* each are:
. * Object call member function pointer;
The->* object pointer invokes the member function pointer.
The standard also states that some operators can support "unary operations" and "two-dollar operations" at the same time:
The following sections demonstrate how detailed operator overloading methods should be implemented by implementing several classes that simulate built-in types.
Some precautions
When implementing operator overloading, you should be aware that:
- Operator overloading does not change the precedence and binding of operators , such as/precedence ratio-high;
- Operator overloading does not change the limit of the number of operands to some operators , such as + can only have two operands;
Analog integer Integer
Recall that the C + + support for integer type support those operations? Details are:
Arithmetic operations:
Is. such as +a; negative, such as-A;
Plus, such as a + B; such as a * b; such as A/b. Residual (modulus), such as a% B;
Self-increment reduction (integer-specific):
Self-increasing, such as a++,++a; self-reduction, such as a--,--a;
Comparison operation:
Greater than, such as a > b; less than, such as a < b;
Equals. such as a = = B. Not equal to, such as a! = B.
Greater than or equal. such as a >= B. is less than or equal to. such as a <= B.
Bit operations:
Bitwise inverse. such as ~a.
Move left, such as a << 2. Move right, such as a >> 3;
Bitwise with, such as A & B. bitwise OR, as a | b; bitwise XOR, as a ^ B;
Assignment operation:
Assigned value. A = 5;
Compound Assignment:
+ =. -=,*=,/=,%=, (Arithmetic operation and assignment operation compound)
&=. |=,^=,<<=,>>=. (Bitwise operations and Assignment operations compound)
Here is the code for this integer:
Class Integer{public:integer (int ival): value (ival) {}integer (const integer& iobj): Value (iobj.value) {}//operator Int () {return value;}//conversion to built-in Intinteger operator+ () const {return Integer (value);} Integer operator-() const {return Integer (-value);} Integer operator+ (const integer& RHS) Const {return Integer (value + rhs.value);} Integer operator-(const integer& RHS) Const {return Integer (value-rhs.value);} Integer operator* (const integer& RHS) Const {return Integer (value * rhs.value);} Integer operator/(const integer& RHS) Const {return Integer (value/rhs.value);} Integer operator% (const integer& RHS) Const {return Integer (value% rhs.value);} Prefixinteger operator++ () {return Integer (++value);} Integer operator--() {return Integer (--value);} Suffixinteger operator++ (int) {int old = value, value++; return Integer (old);} Integer operator--(int) {int old = value; value--; return integer (old);} Compare:bool OPERATOR≪ (const integer& RHS) Const {return value < Rhs.value;} BOOL Operator> (const integer& RHS) Const {return value > rhs.value;} BOOL operator== (const integer& RHS) Const {return value = = Rhs.value;} BOOL Operator!= (const integer& RHS) Const {return value! = Rhs.value;} BOOL Operator<= (const integer& RHS) Const {return value <= rhs.value;} BOOL Operator>= (const integer& RHS) Const {return value >= rhs.value;} Bit Operations:integer operator~ () const {return Integer (~value);} Integer operator<< (unsigned n) const {return Integer (value << n);} Integer operator>> (unsigned n) const {return Integer (value >> n);} Integer operator& (const integer& RHS) Const {return Integer (value & Rhs.value);} Integer operator| (const integer& RHS) Const {return Integer (value | rhs.value);} Integer operator^ (const integer& RHS) Const {return Integer (value ^ rhs.value);} Assignment:integer operator= (const Integer& RHS) {return value = Rhs.value;} Compound Assignment:integer operator+= (const integer& RHS) {return value + = Rhs.value;} Integer operator-= (const integer& RHS) {return value-= Rhs.value;} Integer operator*= (const integer& RHS) {return value *= rhs.value;} Integer operator/= (const integer& RHS) {return value/= rhs.value;} Integer operator%= (const integer& RHS) {return value%= rhs.value;} Integer operator&= (const integer& RHS) {return value &= rhs.value;} Integer operator|= (const integer& RHS) {return value |= rhs.value;} Integer operator^= (const integer& RHS) {return value ^= rhs.value;} Integer operator<<= (const integer& RHS) {return value <<= rhs.value;} Integer operator>>= (const integer& RHS) {return value >>= rhs.value;} Private:int value;};
When you implement an operator overload function. It is important to note whether you want to add a const at the end.
This depends on whether the operation will change the member values of the current object. If it is not changed, then the change is added.
The integer class simply shows how to use operator overloading and does not have much useful value.
A test of the integer class:
void Testinteger () {Integer i = 123; #define Seprater ": \ T" #define Trace_integer (iobj) printf (#iobj seprater "%d\n", (iobj) . Value) #define TRACE_BOOL (exp) printf (#exp seprater "%s\n", (exp)? "True": "false") #define TRACE_HEX (iobj) printf (#iobj seprater "%p\n", (iobj). Value) Trace_integer (i); Trace_integer (+i); Trace_integer (-i); INTEGER j = 5; Trace_integer (I+J); Trace_integer (I-J); Trace_integer (I*J); Trace_integer (i/j); Trace_integer (I%J); Trace_integer (++i); Trace_integer (i); Trace_integer (i.); Trace_integer (i); Trace_integer (i++); Trace_integer (i); Trace_integer (i--); Trace_integer (i); Trace_bool (I>J); Trace_bool (I<J); Trace_bool (I==J); Trace_bool (I!=J); Trace_bool (I>=J); Trace_bool (I<=J); Trace_hex (i); Trace_hex (~i); Trace_hex (I<<4); Trace_hex (I>>4); Trace_hex (i<<24); Trace_hex (i & ~0XF); I & ~0xf <<== same as ==>> I & Integer (~0XF), because C + + implicit conversion. Trace_hex (i | 0xF0); Trace_hex (i ^ 0xF0); Trace_integer (i); Trace_integer (j); Trace_inteGER (I=J); Trace_integer (I+=J); Trace_integer (I-=J); Trace_integer (I*=J); Trace_integer (i/=j); j = 3; Trace_integer (I%=J);}
The output of the test is as follows:
I:123+i:123-i:-123i+j:128i-j:118i*j:615i/j:24i%: 3++i:124i:124--i:123i:123i++:123i:124i--:124i:123i>j:truei <j:falsei==j:falsei!=j:truei>=j:truei<=j:falsei:0000007B~i:FFFFFF84i<<4:000007B0i>> 4:00000007i<<24:7b000000i & ~0xf:00000070i | 0XF0:000000FBI ^ 0xf0:0000008bi:123j:5i=j:5i+=j:10i-=j:5i*=j:25i/=j:5i%=j:2
Analog pointer pointer
Recall the native pointers that support those operations?
Details are:
*, dereference. Get T from t*
[], subscript operation
+ +, self-increasing
---Self-reduction
+, addition
-, subtraction
One thing worth noting is that:
- Each type corresponds to a pointer, such as an int corresponding int*;
- The return result of the dereference and subscript operations can do the "Lvalue" (the value to the left of the assignment operator). is able to assign values).
- The addition and subtraction of pointers, which are in the size of the current type of the pointer. That is: if there is a pointer p, then (size_t) (p + 1) = = (size_t) p + sizeof (*P)
To implement the 1,pointer type must be implemented as a class template;
Pointer is implemented as a class template, and its data member can be a native pointer, which can support the addition and subtraction of native pointers very naturally.
The pointer class is implemented as follows:
Template <typename t>class Pointer {public:pointer (): ptr_ (0) {}pointer (t* ptr): Ptr_ (PTR) {}//operator t* () {RE Turn ptr_; }//Implicit conversion. t* get () const {return ptr_;} t& operator* () const {return *ptr_;} t* operator-> () const {return ptr_; printf ("operator-> () \ n");} t& operator[] (int offset) const {return ptr_[offset];} Pointer<t> operator++ () {return Pointer (++PTR_);}//Prefixpointer<t> operator--() {return Pointer (--PTR_) ; }//prefixpointer<t> operator++ (int) {return Pointer (ptr_++);}//Suffixpointer<t> operator--(int) {return Pointer (ptr_--); }//suffixpointer<t> operator+= (int off) {return Pointer (ptr_ + = off);} pointer<t> operator-= (int off) {return Pointer (ptr_ = off);} pointer<t> operator+ (int off) const {return Pointer (ptr_ + off);} pointer<t> operator-(int off) const {return Pointer (Ptr_-off);} Private:t* ptr_;};
The pointer class simulates only the general operation of pointers, and does not consider the topic "Resource management through pointers", and does not guarantee the actual behavior of delete ptr.
Here is the test procedure for this class:
Template<typename t>ostream& operator<< (ostream& out, const pointer<t>& PTR) {out < < Ptr.ptr_;return out;} #define TRACE (FMT, exp) printf (#exp ": \ T" FMT, (exp)) #define TRACE (exp) cout << #exp << ": \ T" << (exp) << Endl#define array_size (a) sizeof (a)/sizeof (a[0]) int ia[] = {123, 456, 789, 111, 222, 333};void Testpointer () {f or (int i=0; i<array_size (IA); ++i) {printf ("%p:%d\n", &ia[i], ia[i]);} pointer<int> ptr = &ia[0]; TRACE (PTR); TRACE (IA); TRACE (*PTR); TRACE (ptr[1]); TRACE (++PTR); TRACE (*PTR); TRACE (--PTR); TRACE (*PTR); TRACE (ptr++); TRACE (*PTR); TRACE (ptr--); TRACE (*PTR); TRACE (ptr+=2); TRACE (*PTR); TRACE (ptr-=2); TRACE (*ptr);p tr = &ia[3]; TRACE (ptr+2); TRACE (* (ptr+2)); TRACE (ptr-2); TRACE (* (ptr-2));p tr[0] = 555; TRACE (Ptr[0]); *ptr = 666; TRACE (*ptr);}
The output of the test program is as follows:
0X603090:1230X603094:4560X603098:7890X60309C:1110X6030A0:2220X6030A4:333PTR:0X603090IA:0X603090*PTR:123PTR[1] : 456++ptr:0x603094*ptr:456--ptr:0x603090*ptr:123ptr++:0x603090*ptr:456ptr--:0x603094*ptr:123ptr+=2:0x603098* ptr:789ptr-=2:0x603090*ptr:123ptr+2:0x6030a4* (ptr+2): 333ptr-2:0x603094* (ptr-2): 456ptr[0]:555*ptr:666
The above test testpointer is not practical to operator->, the following individual test Operator->:
struct Foo {int id;static int count; Foo (): ID (++count) {printf ("Foo::foo (%p) \ n", this);} ~foo () {printf ("Foo::~foo (%p) \ n", this);} void Show () {printf ("Foo.show (%p):%d\n", this, id);}}; int foo::count = 0;void testaccess () {printf ("\n%s (): \ n", __function__); pointer<foo> fptr = new Foo ();//test Operator->fptr->show (); Access member function. TRACE (fptr->id); Access Data Member.delete fptr.get ();}
The output of the test program is:
Testaccess (): Foo::foo (0x133a010) foo.show (0x133a010): 1fptr->id:1foo::~foo (0x133a010)
Overloading of several special operators
The above two classes basically already cover most of the operator overloads, and the following shows several "rare" operator overloads:
#define Trace_call puts (__function__) class operand{public:void operator, (const operand& RHS) const {Trace_call;} void operator, (int a) const {Trace_call;} void operator, (int a, int b) const {Trace_call;}//Error:operator, with only one parameter void operator->* (int a) const {print F ("%s (%d) \ n", __function__, a); }};
Test procedure:
void Testoperand () {Operand OP1, op2;op1, OP2; operator,op1->*123; operator->*}
Program output:
operator,operator->* (123)
operator new AND operator delete
For the overloads of operator new and operator Delete, the next time you write another blog explanation.
Which operator overloads of C + + can be overloaded?