Operator overloading is one of the most important language features of C + +, and this article will use code examples to answer--c++ which operators can be overloaded? How do I reload? What do I need to be aware of 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", as follows:
Of these, the "," (comma operator) is seldom used.
The standard also specifies an operator that cannot be overloaded :
Where, "::" is the scope operator,
"?:" is the conditional operator.
The two less-used operators are. * and->*, respectively:
. * Object call member function pointer;
The->* object pointer invokes the member function pointer;
The standard also states that some operators can support both "unary operations" and "two-dollar operations":
The following is a demonstration of how the concrete operator overloading method 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;
- The operator overload does not change the limit of the number of operands to the operand, such as + can only have two operands;
Analog integer Integer
Recall that the C + + integer support supports those operations? Specifically:
Arithmetic operations:
Positive, such as +a; negative, such as-A;
Plus, such as a + B, minus, such as a-B, multiply, such as a * B., except, for example, A/A, the remainder (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 to, such as a >= B; less than equals, such as a <= B;
Bit operations:
bitwise inversion, such as ~a;
Shift left, such as a << 2, right, such as a >> 3;
Bitwise AND, such as A & B; bitwise OR, as a | b; bitwise XOR, as a ^ B;
Assignment operation:
Assign 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 implementing operator overloading functions, you need to be aware of whether you want to add a const at the end?
This depends on whether the operation will change the member value of the current object, and if it does not, the change will be added.
The integer class is just to show how to use operator overloading and has little practical 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 this 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
Think back to the native pointers that support those operations?
Specifically:
*, 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 to a int*;
- The return result of the dereference and subscript operations can be "Lvalue" (the value to the left of the assignment operator, which can be assigned to a value);
- The addition and subtraction of pointers-is 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 naturally support the addition and subtraction of native pointers.
The following pointer classes are 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", nor does it guarantee the actual behavior of delete ptr.
The following are the test programs 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 used to OPERATOR->, and the following test operator-> separately;:
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?