Operator overloading in C++

In C++ the overloading principle put on not only to functions, but to operators also.  A programmer can offer his or her own operator to a class by overloading the built-in operator to do some exactcalculation when the operator is used on objects of that class.  It surely can be, making it very easy to write code that feels natural. On the other hand, operator overloading, like any advanced C++ feature, creates the language more complex. the operators spare towards to have very thorough meaning, and most programmers don’t believe operators to do a lot of work, so overloading operators can be ignored to make code unreadable.
To overload an operator, a distinctive operator function is well-defined inside the class as:

class className
{
    ... .. ...
    public
       returnType operator symbol (arguments)
       {
           ... .. ...
       } 
    ... .. ...
};
  • the returnType is the return type of the function.
  • The returnType of the function is surveyed by operator keyword.
  • Symbol is the operator symbol you need to overload. Like: +, <, -, ++
  • You can pass arguments to the operator function in alike way as functions.

 

Advantages

  • It will act differently liable on the operands delivered. Its named extesibility.·         It is not restricted to work only with original Data Type.·          By using this overloading we can simply access the objects to do any operations.·          It sorts code much more readable.·         By overloading standard operators on a class, you can abuse the awareness of the users of that class. This leases users program in the language of the problem area rather than in the language of the machine.

NEED some more points here

  Limitations

  • Invention of new operators is not allowable.

Example:

void operator @ (int) ; //illegal, @ is not a built-in operator or a type name

  • Neither the preference nor the number of arguments of an operator may be changed.

An overloaded && for example, must have exactly two arguments.

  • Some operators cannot be overloaded:

-Direct member access operator                                                    .

-De-reference pointer to class member operator                        .*

-Scope resolution operator                                                             ::

-Conditional operator                                                                      ?:

-Sizeof operator                                                                                sizeof

  • the new casting operators may not be loaded.like these,

static_cast<>, dynamic_cast<>, reinterpret_cast<> and const_cast<>, as well as the # and ## preprocessor tokens,

  • Function declarations that change only by return type. Here, you cannot use the next declarations:

int f();

float f();

  • these statements is a static member function declaration. here, you cannot use the following two member function declarations of f():
  • struct A {
  • static int f();
  • int f();

};

    • Function declarations with parameters that differ only since one is a pointer and the other is an array. Example:
      void f(char*);
      void f(char[10]);

The first array dimension is unimportant when distinguishing parameters; all other array dimensions are major.

 Example:

void g(char(*)[20]);

void g(char[5][20]);

The following two declarations are not equal:

void g(char(*)[20]);

void g(char(*)[40]);
  • Function declarations with parameters that vary only because one is a function type and the other is a pointer to a function of the identical type.

Example:

    • void f(int(float));

void f(int (*)(float));

  • Function declarations with parameters that fluctuate only as of cv-qualifiers const, volatile, and restrict. This limitation only put on if any of these qualifiers seems at the furthest level of a parameter type specification.

Example:

•	int f(int);
•	int f(const int);
int f(volatile int);

• you can distinguish parameters with const, volatile and restrict qualifiers if you spread on them within a parameter type specification.
Example:

void g(int*);
void g(const int*);
void g(volatile int*);
The subsequent declarations are also not equivalent:
void g(float&);
void g(const float&);
void g(volatile float&);

• Function declarations with parameters that vary only since their default arguments differ.
Example:

•	void f(int);
void f(int i = 10);

Example:

Output:

Here,This function is named when ++ operator operates on the object of Test class .

In the program,void operator ++ () operator function is clear (inside Test class).

This function increases the value of count by 1 for t object. 

 Unary operators overloading

  • There are total four unary arithmetic operators:
  • the sign operators + and –

The sign operator – returns the value of the operand however inverts the sign.

The sign operator + does no useful operation, just returning the value of its operand.

  • the increment operator ++ and decrement operator –.

++i i is incremented first and the fresh value of i is then applied, i++ the original value of i is applied before i is incremented.

The decrement operator — adjusts the operand by decreasing the value of the operand by 1. As the sample program opposite shows, prefix or postfix notation can be used with –.

Example: float val(5.0);  cout << val++ – 7.0/2.0;

  • Operator precedence regulates the order of evaluation, i.e. how operators and operands are gathered. Here, ++ has the uppermost precedence and / has a higher precedence than -. The example is calculated as follows: (val++) – (7.0/2.0). The outcome is 1.5, as val is incremented later. If two operators have equivalent precedence, the expression will be calculated as shown in column three of the table.

Example: 3 * 5 % 2 is equal to (3 * 5) % 2

Binary operators overloading

  • you overload a binary operator with any a nonstatic member function that has one parameter, or else a nonmember function that involves of two parameters.
  • Assume a binary operator @is termed with the statement t @ u,

here t is an object of type T, also u is an object of type U.

A nonstatic member function that loads this operator would have the form as:

return_type operator@(T)

  • A nonmember function that overloads the exactly similar operator would have the following form:

return_type operator@(T, U)

  • An overloaded binary operator may return any type.

In this example overloads the * operator:

call x * y is in use as x.operator*(y). The call x * z is taken as operator*(x, z).

  Relational operators overloading

  • You can likewise overload Relational operator like== , != , >= , <=  to relate two user-defined object.

Example:

 Input/Output operators overloading

  • Overloaded to achieve input/output for user defined datatypes.
  • Left Operand will be of formsostream& and istream&
  • Function overloading this operator must be a Non-Member function since left operand is not an Object of the class.
  • It must be a friend function to contact private data members.
  • the<< operator is overloaded with ostream class object cout to print primitive type value output to the screen. Also you can overload << operator in your class to print user-defined type to screen.

Example:

time t1(3,15,48);

cout << t1;

Example:

Output:

++ and — operators overloading

The increment and decrement operators fall into a distinctivegrouping.it covers the categories as,

  • Preincrement and postincrement
  • Predecrement and postdecrement

if you write overloaded operator functions, it can be useful to implement distinct versions for the prefix and postfix versions of these operators.

The prefix form of the operator is statedclosely the similarmethod as any other unary operator; the postfix form obtains an additional argument of type int.

Here see  prefix and postfix increment and decrement operators for the Point class:

The same operators can be well-defined in file scope :

friend Point& operator++( Point& )      // Prefix increment

friend Point& operator++( Point&, int ) // Postfix increment

friend Point& operator–( Point& )      // Prefix decrement

friend Point& operator–( Point&, int ) // Postfix decrement

The argument of type int that signifies the postfix form of the increment or decrement operator is not frequently used to pass arguments. It typicallyholds the value 0:

here no syntax for using the increment or else decrement operators to pass these values other than explicit invocation, as revealed in the preceding code. A more straighttechnique to carry out this functionality is to overload the addition/assignment operator (+=).

  Assignment operators overloading

The assignment operator  is used to facsimile values from one object to a first-hand at present existing object.

If a new object does not have to be made before the copying can take place, the assignment operator is used.

Overloading the assignment operator

Overloading the assignment operator (operator=) is correctlyopen, with one exactattention that we’ll get to. The assignment operator must to be overloaded as a member function.

Output:

Function call () operator overloading

  • The function call operator, when overloaded, does not alter how functions are called. Practically, it adjusts how the operator is to be taken when applied to objects of a given type.
  • when the function call operator is overloaded, operator(), with a nonstatic member function that has a limited number of parameters. If you overload a function call operator for a class its declaration will have the form like this:

return_type operator()(parameter_list)

  • Conflicting all other overloaded operators, one can distribute default arguments and contractions in the argument list for the function call operator.

Example :

Here,The function call a(5, ‘z’, ‘a’, 0) is assumed as a.operator()(5, ‘z’, ‘a’, 0). This demands void A::operator()(int a, char b, …). The function call a(‘z’) is taken as a.operator()(‘z’). This demands void A::operator()(char c, int d = 20). The compiler would not permit the function call a() as its argument list does not complement any function call parameter list defined in class A.

Example:

Here, the function call operator for objects of class Point. If you give an object of Point like a function and pass it two integer arguments, the function call operator will enhance the values of the arguments you passed to Point::x and Point::y respectively. 

 Subscripting [] operator overloading

Here are some useful particulars about overloading of [].
1) Overloading of [] may be valuable when we want to check for index out of bound.
2) We must return by reference in function ever since an expression like “arr[i]” can be used an lvalue.

Example:

Output:

Class member access operator -> overloading

  • When overload operator->with a nonstatic member function that has no parameters. The next example shows how the compiler construes overloaded class member access operators:

Here,The statement x->f() is taken as (x.operator->())->f().

  • The operator->is used to implement “smart pointers.” These pointers are objects that act like normal pointers without they make other tasks when you access an object through them, such as automatic object deletion . 

 Virtual Function

  • A virtual function is a member function that is specified within a base class and redefined by a derived class.
  • To create virtual function, go before the function’s declaration in the base class with the keyword virtual. When a class comprising virtual function is inherited, the derived class redefines the virtual function to garb its own desires.
  • Base class pointer can plugto derived class object. then using base class pointer if we request some function which is in both classes, then base class function is send for.

However if we need to invoke derived class function using base class pointer, it can be done by describing the function as virtual in base class, this is how virtual functions upkeep runtime polymorphism.
Example:

Here, Output is 2 ever since pA points to object of B too show() is virtual in base class A.

Pure Virtual Functions

these are virtual functions with no definition. They initialise with virtual keyword plus ends with = 0. Here is the syntax for a pure virtual function,

virtual void f() = 0;

  • Pure Virtual functions can be given a small definition in the Abstract class, which you want all the derived classes to have. Still you cannot create object of Abstract class.
  • Also, the Pure Virtual function must be defined outside the class definition. If you will define it inside the class definition, complier will give an error. Inline pure virtual definition is Illegal.

Output :

Pure Virtual definition

Implementation of Virtual Function in Derived class 

 Abstract Class

Abstract Class is a class which covers atleast one Pure Virtual function in it. Abstract classes are used to offer an Interface for its sub classes. Classes inheriting an Abstract Class must deliver definition to the pure virtual function, or else they will also convert abstract class.

Features of Abstract Class

  1. Abstract class cannot be instantiated, but pointers and references of Abstract class type can be formed.
  2. Abstract class can have regular functions and variables along with a wholesome virtual function.
  3. Abstract classes are mostly used for Up casting, so that its derived classes can use its interface.
  4. Classes getting an Abstract Class must implement all pure virtual functions, or else they will turn out to be Abstract too.

Example of Abstract Class

Output :

Implementation of Virtual Function in Derived class

Here, Base class is abstract, with pure virtual show() function, hence we cannot produce object of base class.

When we produce a pure virtual function in Abstract class, we holdup a space for a function in the VTABLE, but doesn’t put any address in that slot. Therefore the VTABLE will be incomplete.

As the VTABLE for Abstract class is imperfect, from now the compiler will not let the creation of object for such class and will show an error message whenever you attempt to do so.

 

Leave A Comment

Your email address will not be published. Required fields are marked *