C#. Overloading of operators. General information. Overloading of unary operators

Operators overloading. General information. Overloading of unary operators , !, ++,


Contents


Search other resources:

1. The concept of operator overloading

In the C# language, it is possible to set an operator (+, -, != and others) for a specific class or structure, which can be used to perform any action. As a rule, these actions are performed on objects of this class (structure). Representing actions through understandable (natural) statements improves the perception of program code. Thus, the use of well-known operators can be both for basic types (int, double, char and others), and for user-defined classes (user-defined types). The mechanism for specifying standard operators for a given class or structure in order to improve the readability of programs is called operator overloading. Operators can be overloaded for both classes and structures.

Many standard classes implement overloading of many operators. For example, the String class has overloaded operators == and !=, which makes it convenient to compare two strings for equality (inequality).

 

2. Requirements and restrictions that are imposed when overloading operators

When performing operator overloading in classes, a number of requirements must be met:

  • to implement the overload, you need to use public static methods declared in the class;
  • it is forbidden to use the ref or out modifiers in the operator method;
  • in an operator method, the type of the parameter or the type of the return value must match the type (class) in which this operator is overloaded.

The following restrictions are also imposed on operator overloading:

  • overloading does not change the priority of operators;
  • when overloading the operator, the number of operands used cannot be changed;
  • not all operators can be overloaded.

 

3. List of operators that can and cannot be overloaded

Not all operators allow overloading. The table below lists the operators that can be overloaded.

Operators Category of operators
Reversal of sign
! Logical negation
~ Addition to 1
++, −− Increment, decrement
true, false Object truth
+, , *, /, % Arithmetic operators
&&, || Logical operators
&, |, ^, <<, >> Bit operators
==, !=, <, >, <=, >= Comparison operators
[ ] Array element access operation
( ) Cast operations

The following is a list of operators that cannot be overloaded.

Operators Category
+=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>= Shorthand assignment operators
= Assignment
. Access to elements
?: Ternary conditional operator
new Object creation
as, is, typeof Get information about type
->, sizeof, *, & Accessible in unsafe code

 

4. The general form of operator overloading in a class. The operator keyword

To overload an operator in a class, use the operator keyword with the following syntax.

public static return_type operator op(parameters)

where

  • op – the operator to be overloaded (+, –, != etc.);
  • return_type – the type that is returned when using the op operator;
  • parameters – the list of parameters that the operator receives. For unary operators (-, !, ++, –) parameters contains only 1 parameter, for binary operators – 2 parameters.

 

5. Features of overloading unary operators

Unary operators that can be overloaded include the following operators:

  •  – unary minus;
  • ! – logical negation;
  • ++ – increment;
  • –– – decrement.

Since all overloaded operators are static methods, they do not receive the this pointer of the current instance. As a consequence, all operator methods that overload unary operators take one parameter. This parameter must be a class type.

In the most general case, the unary operator overload in the ClassName class is as follows

class ClassName
{
  ...

  public static return_type op(ClassName param)
  {
    // Actions performed
    // ...
  }
}

where

  • op – designation of one of the unary operators , !, ++, ––;
  • param – some parameter;
  • return_type – the return type. It can be any type used in the program.

After that, the op statement can be used on the class ClassName something like this

value = op Obj;

where

  • value – the resulting value of type return_type;
  • Obj – an instance of the ClassName class.

For example, if the ++ operator is overloaded, then the call will be

value = ++Obj;

 

6. Example of overloading a unary operator (minus)

The example shows an overload of the unary operator (minus) using the example of a class that describes a complex number. With the help of an overloaded operator, the signs of the real and imaginary parts of a complex number are reversed.

using System;

namespace ConsoleApp6
{
  class Complex
  {
    // Internal fields of the class
    private double re, im;

    // Constructor
    public Complex(double re, double im)
    {
      this.re = re;
      this.im = im;
    }

    // Internal field access properties
    public double Re
    {
      get { return re; }
      set { re = value; }
    }

    public double Im
    {
      get { return im; }
      set { im = value; }
    }

    // Operator method that overloads the unary operator '-'
    public static Complex operator-(Complex cm)
    {
      return new Complex(-cm.re, -cm.im);
    }

    // Method that outputs the state of the current instance
    public void Print(string msg)
    {
      Console.Write(msg + " => ");
      Console.Write(re);
      if (im >= 0)
        Console.Write("+");
      Console.WriteLine(im.ToString() + "*j");
    }
  }

  internal class Program
  {
    static void Main(string[] args)
    {
      // Create an instance of the Complex class
      Complex c1 = new Complex(2.4, -3.8);

      // Get the state of an instance
      c1.Print("c1");   // c1 => 2.4-3.8*j

      // Create a reference to Complex class
      Complex c2;

      // Assign to reference the return result from the overloaded operator -
      c2 = -c1; // Complex::operator-(c1);

      // Print the state of the instance c2
      c2.Print("c2");   // c2 => -2.4+3.8*j

      Console.ReadKey();
    }
  }
}

Result

c1 => 2.4-3.8*j
c2 => -2.4+3.8*j

 

7. An example of overloading the unary operator ! (negation)

On the example of a class that describes a triangle along its sides, an overload of the unary operator ! is implemented. The operator method returns true if the triangle is equilateral within the specified precision. Otherwise, false is returned.

The example demonstrates only a minimal set of methods for the purpose of demonstrating the overload of the ! (negation).

using System;

namespace ConsoleApp6
{
  class Triangle
  {
    // Internal fields of the class - coordinates of the extreme points of the triangle
    private double x1, y1, x2, y2, x3, y3;

    // Конструктор
    public Triangle(double x1, double y1, double x2, double y2, double x3, double y3)
    {
      this.x1 = x1;
      this.y1 = y1;
      this.x2 = x2;
      this.y2 = y2;
      this.x3 = x3;
      this.y3 = y3;
    }

    // An operator method that overloads the unary operator !.
    // The method returns true if the lengths of the sides are equal to 5 decimal places
    public static bool operator!(Triangle tr)
    {
      // Precision - 5 decimal places
      double eps = 1E-5;

      // Distance between points 1 - 2
      double a = Math.Sqrt((tr.x1 - tr.x2) * (tr.x1 - tr.x2) +
      (tr.y1 - tr.y2) * (tr.y1 - tr.y2));

      // Distance between points 1 - 3
      double b = Math.Sqrt((tr.x1 - tr.x3) * (tr.x1 - tr.x3) +
        (tr.y1 - tr.y3) * (tr.y1 - tr.y3));

      // Distance between points 2 - 3
      double c = Math.Sqrt((tr.x2 - tr.x3) * (tr.x2 - tr.x3) +
        (tr.y2 - tr.y3) * (tr.y2 - tr.y3));

      return (Math.Abs(a - b) < eps) &&
        (Math.Abs(b - c) < eps) &&
        (Math.Abs(a - c) < eps);
    }
  }

  internal class Program
  {
    static void Main(string[] args)
    {
      // Create the instance of Triangle class
      Triangle tr = new Triangle(1, 1, 2, 2, 3, 1);

      // Call the overloaded Triangle::operator!()
      if (!tr)
        Console.WriteLine("The sides of the triangle are equal");
      else
        Console.WriteLine("The sides of the triangle are not equal");

      Console.ReadKey();
    }
  }
}

Result

The sides of the triangle are not equal

 

8. Example of overloading unary operators ++, (increment, decrement)

The unary increment (++) and decrement (–) operators can also be overloaded. There is no difference in C# when overloading the prefix or postfix form of the increment and decrement operators. The prefix form is overloaded, which has the same effect as the postfix form.

The example implements the Point class, which describes a point on the coordinate plane. For demonstration purposes, operator functions are overloaded in the class

public static Point operator++(Point pt);
public static Point operator--(Point pt);

In these functions, the value of the x, y coordinates increases and decreases by 1, respectively.

using System;

namespace ConsoleApp6
{
  class Point
  {
    // Internal fields - coordinates of a point
    private double x, y;

    // Constructor
    public Point(double x, double y)
    {
      this.x = x;
      this.y = y;
    }

    // Properties of access to internal fields
    public double X
    {
      get { return x; }
      set { x = value; }
    }

    public double Y
    {
      get { return y; }
      set { y = value; }
    }

    // A method that prints the internal state of a class
    public void Print(string msg)
    {
      Console.WriteLine(msg + " => ( " + x + "; " + y + ")");
    }

    // Methods that overload the increment (++) and decrement (--) operators
    public static Point operator++(Point pt)
    {
      return new Point(pt.x + 1, pt.y + 1);
    }

    public static Point operator--(Point pt)
    {
      return new Point(pt.x - 1, pt.y - 1);
    }
  }

  internal class Program
  {
    static void Main(string[] args)
    {
      // 1. Declare an instance of the Point class
      Point pt1 = new Point(2, 8);

      // 2. Call the postfix form of the increment operator ++
      pt1++; // the overloaded ++ operator for the Point class is called

      // 3. Print the state of the pt1 instance
      pt1.Print("pt1"); // pt1 => ( 3; 9)

      // 4. Call the prefix form of decrement operator --
      --pt1;

      // 5. Display state of instance pt1 again
      pt1.Print("pt1"); // pt1 => ( 2; 8)

      Console.ReadKey();
    }
  }
}

Result

pt1 => ( 3; 9)
pt1 => ( 2; 8)

 

9. Example of overlading unary operator ~ (addition to 1)

The example demonstrates overloading the unary ~ (tilde) operator.

The Integer class is declared, which describes a non-negative integer. The following operator method is declared in the class

public static Integer operator~(Integer num)

which overloads the ~ operator. The method returns an instance of the Integer class in which the number is reversed (read in reverse order).

using System;

namespace ConsoleApp6
{
  // A class that describes an integer value
  // that can only be positive and has additional properties
  class Integer
  {
    // Internal field - number
    private int value;

    // Constructor
    public Integer(int value)
    {
      if (value < 0)
        this.value = -value;
      else
        this.value = value;
    }

    // Access properties
    public int Value
    {
      get { return value; }
      set {
        if (value < 0)
          this.value = -value;
        else
          this.value = value;
      }
    }

    // The ~ operator overload method
    // The method inverts the number. For example, 2351 => 1532
    public static Integer operator~(Integer num)
    {
      int result = 0;
      int t;
      int pow;

      // Determine the order of the number
      t = num.Value / 10;
      pow = 1;
      while (t > 0)
      {
        t = t / 10;
        pow *= 10;
      }

      // Form the resulting number
      t = num.Value;
      while (t>0)
      {
        result = result + (t % 10) * pow;
        t = t / 10;
        pow = pow / 10;
      }

      return new Integer(result);
    }

    // The method that outputs the internal field.
    public void Print(string msg)
    {
      Console.WriteLine(msg + " => " + value);
    }
  }

  internal class Program
  {
    static void Main(string[] args)
    {
      // Declare an instance of the Integer class
      Integer num1 = new Integer(25631);

      // Display the instance value
      num1.Print("num1");

      // Call a method that overloads the ~ operator
      Integer num2 = ~num1;

      // Display the result
      num2.Print("num2");

      Console.ReadKey();
    }
  }
}

Result

num1 => 25631
num2 => 13652

 


Related topics