< C++ .NET Operator Overloading 7 | Main | Supplementary Note 2 >


 

 

Supplementary Notes 1

Let Have A Break In Playing With Visual C++ .Net!

 

 

  1. C++ Operators

  2. Operator Precedence and Associativity

  3. C++ Operator Precedence and Associativity Table

  4. Operator Overloading

  5. Overloadable Operators

  6. Non Overloadable Operators

  7. Example

  8. Overloaded Operators

----------------Next------------------------------

  1. General Rules for Operator Overloading

  2. Example

  3. Implicit Boxing

  4. Example

  5. Explicitly Request Boxing

  6. Use gcnew to Create Value Types and Use Implicit Boxing

  7. Unboxing

  8. Standard Conversions and Implicit Boxing

  9. static Keyword

  10. Static Member Functions

 

 

C++ Operators

 

The following Table contains C++ operators organized by category.

 

 

Category

Description

Symbol

Additive

Addition

Subtraction

+

Assignment

Addition Assignment

Assignment

Bitwise AND Assignment

Bitwise exclusive OR Assignment

Bitwise inclusive OR Assignment

Division Assignment

Left shift assignment

Modulus Assignment

Multiplication Assignment

Right shift assignment

Subtraction Assignment

+=

=

&=

^=

|=

/=

<<=

%=

*=

>>=

–=

Bitwise

Bitwise AND

Bitwise exclusive OR

Bitwise inclusive OR

&

^

|

Logical

Logical AND

Logical OR

&&

||

Multiplicative

Division

Modulus

Multiplication

/

%

*

Postfix

Cast

Function call

Member access

Postfix decrement

Postfix increment

Subscript

()

( )

. and –>

––

++

[ ]

Relational and Equality

Equality

Greater than or equal to

Greater than

Less than or equal to

Less than

Not equal

==

>=

>

<=

<

!=

Shift

Left shift

Right shift

<<

>>

Unary

Address-of

delete

Indirection

Logical Negation

new

One's Complement

Prefix decrement

Prefix increment

sizeof

Unary Plus Operator

Unary Negation Operator

&

none

*

!

none

~

––

++

none

+

-

Miscellaneous

Comma

Conditional

Pointer-to-member

Reference

Scope resolution

,

? :

.* or –>*

&

::

 

Table 1

 

Operator Precedence and Associativity

 

The C++ language includes all C operators and adds several new operators. Operators specify an evaluation to be performed on one of the following:

  1. One operand (unary operator).

  2. Two operands (binary operator).

  3. Three operands (ternary operator).

 

Operators follow a strict precedence, which defines the evaluation order of expressions containing these operators. Operators associate with either the expression on their left or the expression on their right; this is called "associativity." The following table shows the precedence and associativity of C++ operators (from highest to lowest precedence). Operators in the same segment of the table have equal precedence and are evaluated in the given order in an expression unless explicitly forced by parentheses.

 

C++ Operator Precedence and Associativity Table

 

Operator (arranged in one line!)

Name or Meaning

Associativity

::

Scope resolution

None

., –>, [ ], ( ), ( ), ++, ––, typeid( ), const_cast, dynamic_cast, reinterpret_cast, static_cast

Member selection (object), Member selection (pointer), Array subscript, Function call member initialization, Postfix increment, Postfix decrement, type name, Type cast (conversion), Type cast (conversion), Type cast (conversion), Type cast (conversion).

Left to right.

sizeof, ++, ––, ~, !, , +, &, *, new, delete, ()

Size of object or type, Prefix increment, Prefix decrement, One's complement, Logical not, Unary minus, Unary plus, Address-of, Indirection, Create object, Destroy object, Cast

Right to left.

.*, –>*

Pointer-to-member (objects), Pointer-to-member (pointers)

Left to right

*, /, %

Multiplication, Division, Modulus

Left to right

+,

Addition, Subtraction

Left to right

<<, >>

Left shift Right shift

Left to right

<, >, <=, >=

Less than, Greater than, Less than or equal to, Greater than or equal to

Left to right

==, !=

Equality, Inequality

Left to right

&

Bitwise AND

Left to right

^

Bitwise exclusive OR

Left to right

|

Bitwise inclusive OR

Left to right

&&

Logical AND

Left to right

||

Logical OR

Left to right

e1 ? e2 : e3

Conditional

Right to left

=*, =/, =%, =+, =–, =<<, =>>, =&, =|, =^, =

Assignment Multiplication, assignment Division, assignment Modulus, assignment Addition, assignment Subtraction, assignment Left-shift, assignment Right-shift, assignment Bitwise AND, assignment Bitwise inclusive OR, assignment Bitwise exclusive OR, assignment

Right to left

throw expr

throw expression

Right to left

,

Comma

Left to right

 

Table 2

 

Operator Overloading

 

The operator keyword declares a function specifying what operator-symbol means when applied to instances of a class. This gives the operator more than one meaning, or "overloads" it. The compiler distinguishes between the different meanings of an operator by examining the types of its operands.

type operator operator-symbol(parameter-list)

Example:

static bool operator==(const Operation^, const Operation^);

You can redefine the function of most built-in operators globally or on a class-by-class basis. Overloaded operators are implemented as functions. The name of an overloaded operator is operatorx, where x is the operator as it appears in the following table. For example, to overload the addition operator, you define a function called operator+. Similarly, to overload the addition/assignment operator, +=, define a function called operator+=.

 

Overloadable Operators

 

Operator

Name

Type

,

Comma

Binary

!

Logical NOT

Unary

!=

Inequality

Binary

%

Modulus

Binary

%=

Modulus assignment

Binary

&

Bitwise AND

Binary

&

Address-of

Unary

&&

Logical AND

Binary

&=

Bitwise AND assignment

Binary

( )

Function call

*

Multiplication

Binary

*

Pointer dereference

Unary

*=

Multiplication assignment

Binary

+

Addition

Binary

+

Unary Plus

Unary

++

Increment1

Unary

+=

Addition assignment

Binary

Subtraction

Binary

Unary negation

Unary

––

Decrement1

Unary

–=

Subtraction assignment

Binary

–>

Member selection

Binary

–>*

Pointer-to-member selection

Binary

/

Division

Binary

/=

Division assignment

Binary

<

Less than

Binary

<<

Left shift

Binary

<<=

Left shift assignment

Binary

<=

Less than or equal to

Binary

=

Assignment

Binary

==

Equality

Binary

>

Greater than

Binary

>=

Greater than or equal to

Binary

>>

Right shift

Binary

>>=

Right shift assignment

Binary

[ ]

Array subscript

^

Exclusive OR

Binary

^=

Exclusive OR assignment

Binary

|

Bitwise inclusive OR

Binary

|=

Bitwise inclusive OR assignment

Binary

||

Logical OR

Binary

~

One's complement

Unary

delete

Delete

new

New

conversion operators

conversion operators

Unary

 

Table 3

 

Note: Two versions of the unary increment and decrement operators exist: preincrement and postincrement.

 

Non Overloadable Operators

 

The operators shown in the following table cannot be overloaded. The table includes the preprocessor symbols # and ##.

 

Operator

Name

.

Member selection

.*

Pointer-to-member selection

::

Scope resolution

? :

Conditional

#

Preprocessor convert to string

##

Preprocessor concatenate

 

Table 4

 

Although overloaded operators are usually called implicitly by the compiler when they are encountered in code, they can be invoked explicitly the same way as any member or nonmember function is called:

Point pt;

pt.operator+(3);  // Call addition operator to add 3 to pt.

Example

 

The following traditional C++ code example overloads the + operator to add two complex numbers and returns the result.

// traditional C++ operator overloading

// compile with: /clr

#include "stdafx.h"

#include <iostream>

using namespace System;

using namespace std;

 

struct Complex

{

  Complex(double r, double i) : re(r), im(i) {}

  // Overloaded the addition...

  Complex operator+(Complex &other);

  void Display()

  {

     cout<<"Real part = "<<re<<", "<<"Imaginary part = "<<im<< endl;

  }

  private:

    double re, im;

};

 

// Operator overloaded using a member function

Complex Complex::operator+(Complex &other)

{

   return Complex(re + other.re, im + other.im);

}

 

int main()

{

   Complex a = Complex(1.2, 3.4);

   cout<<"a: ";

   a.Display();

   Complex b = Complex(5.6, 7.8);

   cout<<"b: ";

   b.Display();

   Complex c = Complex(0.0, 0.0);

   cout<<"c: ";

   c.Display();

   cout<<endl;

   c = a + b;

   cout<<"c = a + b: ";

   c.Display();

}

 

Output:

 

 

 

 

 

C++ code example overloads the + operator to add two complex numbers and returns the result

 

Overloaded Operators

 

Operator overloading has changed significantly from Managed Extensions for C++ to Visual C++ 2005. Perhaps the most striking aspect of Managed Extensions is its support for operator overloading or rather, its effective absence. Within the declaration of a reference type, for example, rather than using the native operator+ syntax, one has to explicitly write out the underlying internal name of the operator, in this case, op_Addition. More onerous, however, is the fact that the invocation of an operator has to be explicitly invoked through that name, thus precluding the two primary benefits of operator overloading:

 

  1. The intuitive syntax, and

  2. The ability to intermix new types with existing types.

 

For example:

// operator overloading

// Compile with /clr:OldSyntax

#include "stdafx.h"

 

using namespace System;

 

public __gc __sealed class Operation

{

   public:

      // ...

      Operation(double x, double y, double z);

      static bool    op_Equality(const Operation*, const Operation*);

      static Operation* op_Division(const Operation*, double);

      static Operation* op_Addition(const Operation*, const Operation*);

      static Operation* op_Subtraction(const Operation*, const Operation*);

      // ...

};

 

int main()

{

   Operation *pa = new Operation(0.231, 2.4745, 0.023);

   Operation *pb = new Operation(1.475, 4.8916, -1.23);

 

   Operation *pc1 = Operation::op_Addition(pa, pb);

   Operation *pc2 = Operation::op_Subtraction(pa, pc1);

   Operation *pc3 = Operation::op_Division(pc1, pc2->x);

 

   if (Operation::op_Equality(pc1, pc2))

   // ;

   // ...

}

In the new syntax, the usual expectations of a native C++ programmer are restored, both in the declaration and use of the static operators. Here is the Vector class translated into the new syntax:

 

// operator overloading

// Compile with /clr

#include "stdafx.h"

 

using namespace System;

 

public ref class Operation sealed

{

      public:

            // ...

            Operation(double x, double y, double z);

 

            static bool    operator ==(const Operation^, const Operation^);

            static Operation^ operator /(const Operation^, double);

            static Operation^ operator +(const Operation^, const Operation^);

            static Operation^ operator -(const Operation^, const Operation^);

            // ...

};

 

int main()

{

      Operation^ pa = gcnew Operation(0.231, 2.4745, 0.023);

      Operation^ pb = gcnew Operation(1.475,4.8916,-1.23);

 

      Operation^ pc1 = pa + pb;

      Operation^ pc2 = pa - pc1;

      Operation^ pc3 = pc1 / pc2->x;

     

      if (pc1 == pc2)

            // ;

            // ...

}

 

The following is another Managed Extension of C++ example.

// Operator overloading, Managed Extension for C++

// Compile with /clr:OldSyntax

#include "stdafx.h"

 

using namespace System;

 

// The Dbl struct definition

__value struct Dbl

{

    double val;

    // creation or assignment time

    double hr, min, sec;

    public:

       Dbl(double v)

       {

          val = v;

          // Create new date and time fields

          DateTime dt = DateTime::get_Now();

          hr = dt.get_Hour();

          min = dt.get_Minute();

          sec = dt.get_Second();

       }

       double getVal() { return val; }

       // The addition operator for the Dbl struct

       // lhs - left hand side, rhs - right hand side

       static Dbl op_Addition(Dbl lhs, Dbl rhs)

       {

          Dbl result(lhs.val + rhs.val);

          return result;

       }

       // Adding a Dbl and an int

       static Dbl op_Addition(Dbl lhs, int rhs)

       {

          Dbl result(lhs.val + rhs);

          return result;

       }

       // Adding an int and a Dbl

       static Dbl op_Addition(int lhs, Dbl rhs)

       {

          Dbl result(lhs + rhs.val);

          return result;

       }

       // The equality operator for the Dbl struct

       static bool op_Equality(Dbl lhs, Dbl rhs)

       {

          return lhs.val == rhs.val;

       }

       // The inequality operator for the Dbl struct

       static bool op_Inequality(Dbl lhs, Dbl rhs)

       {

          return !(lhs == rhs);   // calls op_Equality()

       }

       // The equality operator for the Dbl struct

       bool Equals(Object* pOther)

       {

          Dbl* s = dynamic_cast<Dbl*>(pOther);

          if (s == 0) return false;

            return s->val == val;

       }

       // The assignment operator for the Dbl struct

       static Dbl op_Assign(Dbl& lhs, const Dbl& rhs)

       {

          // Copy over the value

          lhs.val = rhs.val;

          // Create new date and time fields

          DateTime dt = DateTime::get_Now();

          lhs.hr = dt.get_Hour();

          lhs.min = dt.get_Minute();

          lhs.sec = dt.get_Second();

          return lhs;

        }

        // The increment operator for the Dbl struct

        static Dbl op_Increment(Dbl d)

        {

          d.val += 1;

          return d;

        }

};

 

int main()

{

   Dbl d1(10.0);

   Dbl d2(20.0);

   Dbl d3(0.0);

   // Add two Dbl’s

   d3 = d1 + d2;

   Console::Write("Value of d3 is ");

   Console::WriteLine(d3.getVal());

   // Add a Dbl and an int

   d3 = d1 + 5;

   Console::Write("Value of d3 is now ");

   Console::WriteLine(d3.getVal());

   // Add an int and a Dbl

   d3 = 5 + d2;

   Console::Write("Value of d3 is now ");

   Console::WriteLine(d3.getVal());

   if (d1 == d2)

      Console::WriteLine("d1 and d2 are equal");

   else

      Console::WriteLine("d1 and d2 are not equal");

   if (d1.Equals(__box(d2)))

      Console::WriteLine("d1 and d2 are equal");

   else

      Console::WriteLine("d1 and d2 are not equal");

   // Create two objects

   Dbl one(0.0);

   Dbl two(10.0);

   // Sleep for five seconds

   Console::WriteLine("Wait... ");

   System::Threading::Thread::Sleep(5000);

   // Do an assignment

   one = two;

   // Create a Dbl, and increment it

   Dbl d5(1.0);

   Console::Write("Initial value of d5 is ");

   Console::WriteLine(d5.getVal());

   // Increment it

   d5++;

   Console::Write("Value of d5 is now ");

   Console::WriteLine(d5.getVal());

   return 0;

}

 

Output:

Operator overloading - Managed Extension of C++ example  

 

The scale down version of the previous program example is shown below.

// Operator overloading

// Compile with /clr:OldSyntax

#include "stdafx.h"

 

using namespace System;

 

// The Dbl struct definition

__value struct Dbl

{

  double val;

  public:

     Dbl(double v)

     {

        Console::WriteLine("In Dbl()...");

        val = v;

     }

     double getVal()

     {

        return val;

     }

     // The addition operator for the Dbl struct

     // lhs - left hand side, rhs - right hand side

     static Dbl op_Addition(Dbl lhs, Dbl rhs)

     {

        Console::WriteLine("In op_Addition()...");

        Dbl result(lhs.val + rhs.val);

        return result;

     }

};

 

int main()

{

   Dbl d1(10.0);

   Dbl d2(20.0);

   Dbl d3(0.0);

 

   d3 = d1 + d2;

   Console::WriteLine("Go to getVal()...");

   Console::Write("Value of d3 is ");

   Console::WriteLine(d3.getVal());

   return 0;

}

 

Output:

Operator overloading - Managed Extension of C++ example scale down version

 

// Operator overloading, new C++

// Compile with /clr

#include "stdafx.h"

 

using namespace System;

 

// The Dbl struct definition

value struct Dbl

{

    double val;

    // creation or assignment time

    double hr, min, sec;

    public:

      Dbl(double v)

      {

        val = v;

        // Create new date and time fields

        DateTime dt = DateTime::Now;

        hr = dt.Hour;

        min = dt.Minute;

        sec = dt.Second;

      }

      double getVal() { return val; }

      // The addition operator for the Dbl struct

      // lhs - left hand side, rhs - right hand side

      static Dbl operator+(Dbl lhs, Dbl rhs)

      {

        Dbl result(lhs.val + rhs.val);

        return result;

      }

      // Adding a Dbl and an int

      static Dbl operator+(Dbl lhs, int rhs)

      {

        Dbl result(lhs.val + rhs);

        return result;

      }

      // Adding an int and a Dbl

      static Dbl operator+(int lhs, Dbl rhs)

      {

        Dbl result(lhs + rhs.val);

        return result;

      }

      // The equality operator for the Dbl struct

      static bool operator==(Dbl lhs, Dbl rhs)

      {

        return lhs.val == rhs.val;

      }

      // The inequality operator for the Dbl struct

      static bool operator!=(Dbl lhs, Dbl rhs)

      {

        return !(lhs == rhs);   // calls op_Equality()

      }

      // The equality operator for the Dbl struct

      virtual bool Equals(Object^ pOther) override

      {

        Dbl^ s = dynamic_cast<Dbl^>(pOther);

        if (s == nullptr) return false;

          return s->val == val;

      }

      // The assignment operator for the Dbl struct

      // cannot use the operator=( , )

      static Dbl op_Assign(Dbl& lhs, const Dbl& rhs)

      {

          // Copy over the value

          lhs.val = rhs.val;

          // Create new date and time fields

          DateTime dt = DateTime::Now;

          lhs.hr = dt.Hour;

          lhs.min = dt.Minute;

          lhs.sec = dt.Second;

          return lhs;

      }

      // The increment operator for the Dbl struct

      static Dbl operator++(Dbl d)

      {

          d.val += 1;

          return d;

      }

};

 

int main()

{

   Dbl d1(10.0);

   Dbl d2(20.0);

   Dbl d3(0.0);

 

   // Add two Dbl’s

   d3 = d1 + d2;

   Console::Write("Value of d3 is ");

   Console::WriteLine(d3.getVal());

   // Add a Dbl and an int

   d3 = d1 + 5;

   Console::Write("Value of d3 is now ");

   Console::WriteLine(d3.getVal());

   // Add an int and a Dbl

   d3 = 5 + d2;

   Console::Write("Value of d3 is now ");

   Console::WriteLine(d3.getVal());

   if (d1 == d2)

      Console::WriteLine("d1 and d2 are equal");

   else

      Console::WriteLine("d1 and d2 are not equal");

   if (d1.Equals((Object^)d2))

      Console::WriteLine("d1 and d2 are equal");

   else

      Console::WriteLine("d1 and d2 are not equal");

   // Create two objects

   Dbl one(0.0);

   Dbl two(10.0);

   // Sleep for five seconds

   Console::WriteLine("Wait... ");

   System::Threading::Thread::Sleep(5000);

   // Do an assignment

   one = two;

   // Create a Dbl, and increment it

   Dbl d5(1.0);

   Console::Write("Initial value of d5 is ");

   Console::WriteLine(d5.getVal());

   // Increment it

   d5++;

   Console::Write("Value of d5 is now ");

   Console::WriteLine(d5.getVal());

   return 0;

}

 

Output:

Operator overloading - new C++ program example

 

 

 

 

Part 1 | part 2

 


 

< C++ .NET Operator Overloading 7 | Main | Supplementary Note 2 >