Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

unit 4hjo

Download as pdf or txt
Download as pdf or txt
You are on page 1of 35

Programming in C++ Notes :

Unit – 𝚰𝐕

Introduction To Operator Overloading –


Operator overloading in C++ allows you to
define custom behaviors for operators
when they are used with user-defined
datatypes, such as classes and structures.
This feature enables you to make your code
more intuitive and expressive by allowing
objects to behave like built-in datatypes.

Syntax :
returnType operatorSymbol(parameters);

 Operator overloading is done by defining a


function with the keyword operator

1|Page
followed by the operator symbol you want
to overload.

Restriction of Operator Overloading –


Operator overloading in C++ provides great
flexibility, but it also comes with some
restrictions and guidelines to ensure safety,
clarity, and maintainability of the code.
Here are some of the key restrictions and
considerations for operator overloading in
C++ :
1. Precedence and Associativity:
You cannot change the precedence or
associativity of operators through
overloading. Overloaded operators
maintain their original precedence and
associativity.

2|Page
2. Arity of Operators:
You cannot change the number of
operands an operator takes. For
example, the + operator for addition
always takes two operands, and you
cannot change this behavior through
overloading.

3. Semantics Preservation:
Overloaded operators should preserve
the original meaning of the operator as
much as possible. For example,
overloading the + operator for addition
should perform addition-like behavior.

4. Inheritance:
Operator overloading works differently in
the context of inheritance. If a base class
has overloaded operators, those
operators are not automatically inherited
by derived classes. Each class in the

3|Page
inheritance hierarchy must explicitly
overload the operators it needs.

5. Some Operators Cannot Be Overloaded:


Certain operators in C++ cannot be
overloaded. For example, the . (dot)
operator, :: (scope resolution) operator,
?: (ternary conditional) operator, and
sizeof operator cannot be overloaded.

6. Overloading for Built-in Types:


Operators cannot be overloaded for
built-in types like int, float, etc. Operator
overloading is only applicable to user-
defined types, such as classes and
structures.

7. Friendship for Non-Member Overloaded


Operators:
If you overload an operator as a non-
member function and need access to
4|Page
private or protected members of the
class, you may need to declare the
function as a friend of the class.

8. Syntax Constraints:
Overloaded operators must obey C++
syntax rules, including return types,
parameter types, and const-correctness.

Overloading Unary Operators –


Unary operators are those that operate on
a single operand. In C++, unary operators
can be overloaded to define custom
behavior for user-defined types.
Here's how you can overload unary
operators in C++:
Syntax –
returnType operatorSymbol();

 Unary operators can be overloaded as member functions or as non-


member functions.

5|Page
Example –
#include <iostream>
using namespace std;

class Count
{
private:
int value;

public:
// Constructor to initialize value to 5
Count()
{
value = 5;
}

// Overload ++ when used as prefix


void operator++()
{
++value;
}

void display()
{
cout << "Count : " << value << endl;
}
};

int main()
{
Count count1;

// Call the "void operator ++ ()" function


++count1;

count1.display();
return 0;
}

6|Page
Output –
Count : 6

Overloading Binary Operators –


Binary operators are those that operate on
two operands. In C++, binary operators can
be overloaded to define custom behavior
for user-defined types.
Here's how you can overload binary
operators in C++:
Syntax –
returnType operatorSymbol(const Type1& operand1, const Type2& operand2);

Example :
#include <iostream>
using namespace std;
class complex
{
private:
int real, imag;

public:
complex(int r = 0, int i = 0)
{
real = r;

7|Page
imag = i;
}
// Overloading + operator using a member function
complex operator+(const complex &obj) // accessing the complex class via
object's reference
{
complex res;
res.real = real + obj.real; // real part of complex number
res.imag = imag + obj.imag; // imaginary part of complex number
return res;
}
// prints the result in Complex Form
void print()
{
cout << real << "+i" << imag;
}
};
int main()
{
complex c1(5, 6), c2(7, 5);
complex c3 = c1 + c2; // Calls the overloaded + operator
c3.print(); // prints the output
return 0;
}

Output :
Complex Number is : 12 +i11

Type Conversions –
The conversion of a variable from one data
type to another is called Type Conversion in
C++. Type conversion in C++ is most
commonly used to perform mathematical
8|Page
and logical operations on two variables
with different data types.
There are two types of Type Conversions in C++ :
1. Implicit Type Conversion : The Implicit Type
Conversion is where the type conversion is
done automatically by the compiler. It does not
require any effort from the programmer. The
C++ compiler has a set of predefined rules. The
compiler automatically converts one data type
to another based on these rules. Therefore,
implicit type conversion is also known as
automatic type conversion.

Example :
#include <iostream>
using namespace std;
int main()
{
int int_var;
float float_var = 20.5;
int_var = float_var;
// Trying to store the value of float_var in int_var.
cout << "The value of int_var is: " << int_var << endl;
cout << "The value of float_var is: " << float_var << endl;
return 0;
}

Output :
The value of int_var is: 20
The value of float_var is: 20.5

9|Page
2. Explicit Type Conversion : are those
conversions that are done by the programmer
manually. In other words, explicit conversion
allows the programmer to typecast (change)
the data type of a variable to another type.
Hence, it is also called typecasting.

Explicit type conversion in C++ can be done in two


ways :
a) Conversion Using the Assignment Operator :
Explicit typecasting in c++ is done using the
assignment operator is also referred to as a
forced casting. This conversion is done by
explicitly declaring the required data type in
front of the expression.

It can be done in two ways:


1. C-style type casting : This type of casting is
usually used in the C programming
language. It is also known as cast notation.

Syntax –
(datatype)expression;

10 | P a g e
Example :
#include <iostream>
using namespace std;
int main()
{
char char_var = 'a';
int int_var;
// Explicitly converting a character variable to an integer
variable.
int_var = (int)char_var; // Using cast notation.
cout << "The value of char_var is: " << char_var << endl;
cout << "The value of int_var is: " << int_var << endl;
return 0;
}

Output :
The value of char_var is: a
The value of int_var is: 97

2. Function style casting : This type of casting


is usually used in the C programming
language. It is also known as cast notation.

Syntax –
(datatype)expression;

Example :
#include <iostream>
using namespace std;

int main()
{
int int_var = 17;

float float_var;

float_var = float(int_var) / 2;

11 | P a g e
// Explicitly converting an int to a float.

cout << "The value of float_var is: " << float_var <<
endl;

return 0;
}

Output :
The value of float_var is: 8.5

b) Conversion Using the Cast Operator : Besides


using the assignment operator, we can also use
the cast operator for typecasting. The cast
operator forces the conversion of one data type
to another. It is a type of unary operator.

There are 4 types of Casting in C++


programming language. These are :
1. Static Cast
2. Dynamic Cast
3. Const Cast
4. Reinterpret Cast

Pointers –
Pointers in C++ are variables that store
memory addresses. They are powerful
features of the language and allow for
12 | P a g e
dynamic memory allocation, manipulation
of memory, and creation of data structures
like linked lists, trees, and dynamic arrays.
Syntax –
datatype *pointer_name;

 We use the asterisk (*) symbol to designate a variable as a


pointer in C++. The asterisk symbol can be placed anywhere
before the pointer name and after the datatype.

Symbols Used in Pointers :


Symbol Name Description
& Address of operator Used to find the address of a
variable
* Indirection operator Used to access the value at an
address

Example :
#include <iostream>
using namespace std;

int main()
{
int var = 23;

int *ptr;

13 | P a g e
ptr = &var; // address of var is assigned to ptr

cout << "Initial value of var is: " << var << endl;
cout << "Initial value of *ptr is: " << *ptr << endl
<< endl;

// changing the value of var using ptr


*ptr = 50;

cout << "New value of *ptr is: " << *ptr << endl;
cout << "New value of var is: " << var << endl;

return 0;
}

Output :
Initial value of var is : 23
Initial value of *ptr is : 23

New value of *ptr is : 50


New value of var is : 50

Pointers to Object –
Pointers to objects aim to make a pointer
that can access the object, not the
variables. Pointer to object in C++ refers to
accessing an object and is used to store the
address of an object.

14 | P a g e
Syntax 1 –
classname*pointertoobject; // declaring pointer to object

Syntax 2 –
pointertoobject=&objectname; // storing the address of an object into a pointer

 The above syntax can be used to store the address in the pointer to the
object. After storing the address in the pointer to the object, the member
function can be called using the pointer to the object with the help of an
arrow operator.

Example :
#include <iostream>
using namespace std;

class My_Class
{
int num;

public:
void set_number(int value)
{
num = value;
}
void show_number()
{
cout << num << "\n";
}
};

int main()

15 | P a g e
{
My_Class object, *p; // an object is declared and a pointer to it

object.set_number(1); // object is accessed directly


object.show_number();

p = &object; // the address of the object is assigned to p


p->show_number(); // object is accessed using arrow operator

return 0;
}

Output :
1
1

“this” Pointer –
In C++ programming, "this" is a keyword
representing the current class instance. It's
a special pointer that allows you to access
the object's data members and member
functions from within the class.

It serves three primary purposes:


1. Passing the current object as a
parameter to another method.
16 | P a g e
2. Referring to current class instance
variables.

3. Declaring indexers.

Syntax –
Inside a member function, we can use the “this” pointer to access members of
the current object using the arrow operator (->) or the dot operator (.).

Example :
#include <iostream>
using namespace std;
class MyClass
{
private:
int data;

public:
void setData(int data)
{
// Using this pointer to access the member variable
this->data = data;
}

int getData()
{
// Using this pointer to return the value of the member variable
return this->data;
}
};

int main()

17 | P a g e
{
MyClass obj1, obj2;
obj1.setData(10);
obj2.setData(20);

cout << "Data in obj1 : " << obj1.getData() << endl;


cout << "Data in obj2 : " << obj2.getData() << endl;

return 0;
}

Output :
Data in obj1 : 10
Data in obj2 : 20

Pointer to Derived Class –


Pointer to objects of the base class is type
compatible with the pointers to objects of
a derived class. Therefore, a single pointer
variable can be made to point to the
objects belonging to different classes.

Example :
#include <iostream>
using namespace std;
class base
{
public:
int n1;
void show()

18 | P a g e
{
cout << "n1 = " << n1 << endl;
}
};

class derive : public base


{

public:
int n2;
void show()
{
cout << "n1 = " << n1 << endl;
}
};
int main()
{
base b;
base *bptr; // base pointer
cout << "Pointer of base class points to it -" << endl;
bptr = &b; // address of base class
bptr->n1 = 23; // access base class via base pointer
bptr->show();
derive d;
cout << "Pointer of base class pointing to derived class-" << endl;
bptr = &d; // address of derive class
bptr->n1 = 63; // access derive class via base pointer
bptr->show();
return 0;
}

Output :
Pointer of base class pointing to it -
n1 = 23
Pointer of base class pointing to derived class-
n1 = 63

Polymorphism –

19 | P a g e
Polymorphism is an important concept of
object-oriented programming. It simply
means more than one form. That is, the
same entity (function or operator) behaves
differently in different scenarios.
For example, The “+” operator in C++ is
used to perform two specific functions.
When it is used with numbers (integers and
floating-point numbers), it performs
addition and when we use the + operator
with strings, it performs string
concatenation.

Types of Polymorphism –
The polymorphism in C++ can be divided
into two types :
1. Compile Time Polymorphism : In
compile-time polymorphism, a function is
called at the compile time. This type of
polymorphism is also known as static
20 | P a g e
binding or early binding. Function
overloading and operator overloading are
the two types of Compile time
polymorphism and are used to accomplish
compile - time polymorphism.

a) Function Overloading : Function


overloading is defined as the process of
using the same function for different
purposes. Here, the same function can be
used to perform different tasks just by
changing the function signature (number
of arguments, type of arguments). It is an
example of compile-time polymorphism
because which function will get called is
decided at compile time.

Example :
#include <iostream>
using namespace std;
class A
{

public:
// this function is performing the addition of two
Integer value

int Add(int num1, int num2)


{
21 | P a g e return num1 + num2;
}

// this function is performing the addition of three


}

// this function is performing the addition of three


Integer values
// while both the functions is having same name.
int Add(int num1, int num2, int num3)
{

return num1 + num2 + num3;


}
};
int main()
{
A obj;
cout << obj.Add(2, 5) << endl;
cout << obj.Add(8, 2, 1) << endl;
}

Output :
7
11

b) Operator Overloading : Operator


overloading is defined as the process of
assigning additional tasks to operators
without altering the actual meaning of the
operation.
We can make operators work for user-
defined classes by providing the operators
with a special meaning for a data type (this
does not mean that we are changing the
22 | P a g e
actual meaning of the operator, we are just
adding an additional specialty to that
operator). This ability is known as operator
overloading.

2. Run-Time Polymorphism : In runtime


polymorphism, a function is called at the
run time or at the time of program
execution. This type of polymorphism is
also known as dynamic binding or late
binding. Function overriding and virtual
functions are the different types of run-
time polymorphism.

It is more flexible than compile-time


polymorphism as the things are executed
at run time.

a) Function Overriding : In function


overriding, we give a new definition to the
base class method or a function in the
derived class. This means that we override

23 | P a g e
the definition of the base class function in
the derived class. Thus, we have two
definitions of the same function, one in
the base class and the other in the child or
the derived class. The decision of choosing
which function definition is to be called is
decided at the run time. That is the reason
we call it a type of ‘Runtime
polymorphism’.

Example :
#include <iostream>
using namespace std;
class A
{

public:
void func()
{
cout << "Hello world!" << endl;
}
};
class B : public A
{
public:
void func()
{
cout << "Welcome back!" << endl;
}
};
int main()
{

// parent class object


A obj;
obj.func();

// child class object


24 | P a g e
B obj1;
obj1.func();
}
Output :
Hello world!
Welcome back!

 As we can see from the output above, the definition of


the func function is redefined in the derived class. And
thus, this is an example of function overriding.

b) Virtual Function : A virtual function is a


base class member function, which is re-
defined (overridden) by a derived class
and are declared virtual with the help of
“virtual” keyword.

As runtime polymorphism is achieved only


through a pointer (or reference) of base
class type. A base class pointer can point
to the objects of the base class as well as
to the objects of the derived class.

When you refer to a derived class object


using a pointer or a reference to the base
25 | P a g e
class, you can call a virtual function for that
object and execute the derived class’s
definition of the function, otherwise, if you
do not mark the function as the virtual
function, then the base class definition of
that function will be called as the pointer
is of the base class type.

Rules to be remembered while creating


virtual function :

• Virtual functions are always defined in


the base class and their definition is
overridden in a derived class. It is not
mandatory for the derived class to
override the definition, in that case,
the base class version or the definition
of the function will be called.

• Virtual functions should always be


accessed using a pointer or reference
of base class type to achieve runtime
polymorphism.

26 | P a g e
• The function's name, parameters, and
return type of virtual functions should
be the same for both the base class
and the derived class.

• Virtual functions cannot be static.

• A virtual function can be a friend


function of another class.

Example :
#include <iostream>
using namespace std;
// base class
class A
{
public:
virtual void show()
{
cout << "This is a base class...!" << endl;
}
};
// child class
class B : public A
{
public:
void show()
{
cout << "This is a child class...!" << endl;
}
};
int main()
{
A *ptr;
B obj; // Create an object of the derived class
ptr = &obj; // Using a base class pointer to refer to a
derived class object
ptr->show();
27 | P a g e
return 0;
}
Output :
This is a child class...!

Types of Virtual Function :

1. Simple Virtual Functions : Simple


virtual functions are regular virtual
functions declared in a base class and
overridden in derived classes. They
enable polymorphic behavior by
allowing derived classes to provide
their own implementations of the
function.

Example :
#include <iostream>
using namespace std;
// base class
class A
{
public:
virtual void show()
{
cout << "This is a base class...!" << endl;
}
};
// child class
28 | P a g e
class B : public A
{
public:
void show()
public:
void show()
{
cout << "This is a child class...!" << endl;
}
};
int main()
{
A *ptr;
B obj; // Create an object of the derived class
ptr = &obj; // Using a base class pointer to refer to a
derived class object
ptr->show();
return 0;
}

Output :
This is a child class...!

2. Pure Virtual Functions : A pure virtual


function is a virtual function for which
we need not write any function
defined in the base class, only we have
to declare it. It is declared by assigning
0 in the declaration and using the
virtual keyword.

29 | P a g e
Example :
// C++ Program to illustrate the abstract class and virtual
// functions
#include <iostream>
using namespace std;
class Base {
// private member variable
int x;
public:
// pure virtual function
virtual void fun() = 0;
// getter function to access x
int getX()
{
return x;
}
};
// This class inherits from Base and implements fun()
class Derived : public Base {
// private member variable
int y;

30 | P a g e
public:
// implementation of the pure virtual function
void fun()
{
cout << "fun() called";
}
};
int main(void)
{
// creating an object of Derived class
Derived d;
// calling the fun() function of Derived class
d.fun();
return 0;
}

31 | P a g e
3. Virtual Destructor : A virtual
destructor is a special type of virtual
function declared in a base class to
ensure proper destruction of objects
in polymorphic hierarchies. When a
derived class object is destroyed
through a base class pointer, a virtual
destructor ensures that the destructor
of the most derived class is called.

Example :
#include <iostream>

using namespace std;

class Base
{
public:
Base()
{
cout << "Constructor of Base class is called" <<
endl;
}
// Defining virtual destructor.
virtual ~Base()
{
// At last, it will be printed.
cout << "Destructor of Base class is called" <<
endl;
}
};

// Inheriting features of Base class in Child class.


class Child : public Base
32 | P a g e {
public:
Child()
{
int main()
{
Base *b = new Child; // Object refers to the Base
class.
delete b; // Deleting the pointer object.
return 0;
}

Output :
Virtual Function is called in the derived class B.

Abstract Class –
A class that contains a pure virtual function
is known as an abstract class.
We cannot create objects of an abstract
class. However, we can derive classes from
33 | P a g e
them, and use their data members and
member functions (except pure virtual
functions).

Example :
#include <iostream>
using namespace std;

// Abstract class
class Shape
{
protected:
float dimension;

public:
void getDimension()
{
cin >> dimension;
}

// pure virtual Function


virtual float calculateArea() = 0;
};

// Derived class
class Square : public Shape
{
public:
float calculateArea()
{
return dimension * dimension;
}
};

// Derived class
class Circle : public Shape
{
public:
float calculateArea()
{

34 | P a g e
return 3.14 * dimension * dimension;
}
};

int main()
{
Square square;
Circle circle;

cout << "Enter the length of the square: "<<endl;


square.getDimension();
cout << "Area of square: " << square.calculateArea() << endl;

cout << "Enter radius of the circle: "<<endl;


circle.getDimension();
cout << "Area of circle: " << circle.calculateArea() << endl;

return 0;
}

Output :
Enter the length of the square:
4
Area of square: 16
Enter radius of the circle:
2
Area of circle: 12.56

35 | P a g e

You might also like