OOPs-Unit 3
OOPs-Unit 3
Constructors in C++
Constructor is a special method that is invoked automatically at the time of object creation. It is
used to initialize the data members of new objects generally. The constructor in C++ has the
same name as the class or structure. Constructor is invoked at the time of object creation. It
constructs the values i.e. provides data for the object which is why it is known as constructors.
Constructor does not have a return value, hence they do not have a return type.
<class-name> (list-of-parameters);
Example:
#include <iostream>
using namespace std;
class student {
int rno;
char name[10];
double fee;
public:
student()
{
cout << "Enter the RollNo:";
cin >> rno;
cout << "Enter the Name:";
cin >> name;
cout << "Enter the Fee:";
cin >> fee;
}
void display()
{
cout << endl << rno << "\t" << name << "\t" << fee;
}
};
int main()
{
student s; // constructor gets called automatically when
// we create the object of the class
s.display();
return 0;
}
Output:
#include <iostream>
using namespace std;
class student {
int rno;
char name[50];
double fee;
public:
student();
void display();
};
student::student()
{
cout << "Enter the RollNo:";
cin >> rno;
void student::display()
{
cout << endl << rno << "\t" << name << "\t" << fee;
}
int main()
{
student s;
s.display();
return 0;
}
Output:
Types of Constructors:
1. Default Constructors: Default constructor is the constructor which doesn’t take any
argument. It has no parameters. It is also called a zero-argument constructor.
Even if we do not define any constructor explicitly, the compiler will automatically
provide a default constructor implicitly.
class construct {
public:
int a, b;
// Default Constructor
construct()
{
a = 10;
b = 20;
}
};
int main()
{
// Default constructor called automatically
// when the object is created
construct c;
cout << "a: " << c.a << endl << "b: " << c.b;
return 1;
}
Output:
a: 10
b: 20
Student s;
Will flash an error
class Point {
private:
int x, y;
public:
// Parameterized Constructor
Point(int x1, int y1)
{
x = x1;
y = y1;
}
int getX() { return x; }
int getY() { return y; }
};
int main()
{
// Constructor called
Point p1(10, 15);
return 0;
}
Output :
When an object is declared in a parameterized constructor, the initial values have to be passed as
arguments to the constructor function. The normal way of object declaration may not work. The
constructors can be called explicitly or implicitly.
It is used to initialize the various data elements of different objects with different values
when they are created.
It is used to overload constructors.
3. Copy Constructor:
A copy constructor is a member function that initializes an object using another object of
the same class.
Whenever we define one or more non-default constructors (with parameters) for a
class, a default constructor (without parameters) should also be explicitly defined as the
compiler will not provide a default constructor in this case. However, it is not necessary but
it’s considered to be the best practice to always define a default constructor.
Copy constructor takes a reference to an object of the same class as an argument.
Example:
// C++ program to demonstrate the working
// of a COPY CONSTRUCTOR
#include <iostream>
using namespace std;
class Point {
private:
int x, y;
public:
Point(int x1, int y1)
{
x = x1;
y = y1;
}
// Copy constructor
Point(const Point& p1)
{
x = p1.x;
y = p1.y;
}
int main()
{
Point p1(10, 15); // Normal constructor is called here
Point p2 = p1; // Copy constructor is called here
Output:
Destructor:
A destructor is also a special member function as a constructor. Destructor destroys the class
objects created by the constructor. Destructor has the same name as their class name preceded
by a tilde (~) symbol. It is not possible to define more than one destructor. The destructor is
only one way to destroy the object created by the constructor. Hence destructor can-not be
overloaded. Destructor neither requires any argument nor returns any value. It is automatically
called when the object goes out of scope. Destructors release memory space occupied by the
objects created by the constructor. In destructor, objects are destroyed in the reverse of object
creation.
~ <class-name>()
{
}
The syntax for defining the destructor outside the class
<class-name>: : ~ <class-name>(){}
Example:
#include <iostream>
using namespace std;
class Test {
public:
Test() { cout << "\n Constructor executed"; }
Output:
Constructor executed
Destructor executed
Characteristics of a destructor:-
Constructor Overloading:
In C++, We can have more than one constructor in a class with same name, as long as each has
a different list of arguments. This concept is known as Constructor Overloading and is quite
similar to function overloading.
Overloaded constructors essentially have the same name (exact name of the class) and
different by number and type of arguments.
A constructor is called depending upon the number and type of arguments passed.
While creating the object, arguments must be passed to let compiler know, which
constructor needs to be called.
Example:
public:
float area;
void disp()
{
cout<< area<< endl;
}
};
int main()
{
// Constructor Overloading
// with two different constructors
// of class name
construct o;
construct o2( 10, 20);
o.disp();
o2.disp();
return 1;
}
Output:
0
200
Inheritance
When creating a class, instead of writing completely new data members and member
functions, the programmer can designate that the new class should inherit the members of an
existing class. This existing class is called the base class, and the new class is referred to as
the derived class.
During inheritance, the data members of the base class get copied in the derived class and can be
accessed depending upon the visibility mode used. The order of the accessibility is always in a
decreasing order i.e., from public to protected. There are mainly five types of Inheritance in C++
that you will explore in this article. They are as follows:
Single Inheritance
Multiple Inheritance
Multilevel Inheritance
Hierarchical Inheritance
Hybrid Inheritance
To understand the concept of Inheritance, two terms on which the whole concept of inheritance
is based - Child class and Parent class.
Child class: The class that inherits the characteristics of another class is known as the child class
or derived class. The number of child classes that can be inherited from a single parent class is
based upon the type of inheritance. A child class will access the data members of the parent class
according to the visibility mode specified during the declaration of the child class.
Parent class: The class from which the child class inherits its properties is called the parent class
or base class. A single parent class can derive multiple child classes (Hierarchical Inheritance) or
multiple parent classes can inherit a single base class (Multiple Inheritance). This depends on the
different types of inheritance in C++.
The syntax for defining the child class and parent class in all types of Inheritance in C++ is given
below:
class parent_class
{
//class definition of the parent class
};
class child_class : visibility_mode parent_class
{
//class definition of the child class
};
Syntax Description
Uses of Inheritance:-
Inheritance makes the programming more efficient and is used because of the benefits it
provides. The most important usages of inheritance are discussed below:
Code reusability: One of the main reasons to use inheritance is that you can reuse the
code. For example, consider a group of animals as separate classes - Tiger, Lion, and
Panther. For these classes, you can create member functions like the predator () as they
all are predators, canine() as they all have canine teeth to hunt, and claws() as all the three
animals have big and sharp claws. Now, since all the three functions are the same for
these classes, making separate functions for all of them will cause data redundancy and
can increase the chances of error. So instead of this, you can use inheritance here. You
can create a base class named carnivores and add these functions to it and inherit these
functions to the tiger, lion, and panther classes.
Transitive nature: Inheritance is also used because of its transitive nature. For example,
you have a derived class mammal that inherits its properties from the base class animal.
Now, because of the transitive nature of the inheritance, all the child classes of ‘mammal’
will inherit the properties of the class ‘animal’ as well. This helps in debugging to a great
extent. You can remove the bugs from your base class and all the inherited classes will
automatically get debugged.
Modes of inheritance:
Public mode
Protected mode
Private mode
Public mode:
In the public mode of inheritance, when a child class is derived from the base or parent class,
then the public member of the base class or parent class will become public in the child class
also, in the same way, the protected member of the base class becomes protected in the child
class, and private members of the base class are not accessible in the derived class.
Protected mode:
In protected mode, when a child class is derived from a base class or parent class, then both
public and protected members of the base class will become protected in the derived class, and
private members of the base class are again not accessible in the derived class. In contrast,
protected members can be easily accessed in the derived class.
Private mode:
In private mode, when a child class is derived from a base class, then both public and protected
members of the base class will become private in the derived class, and private members of the
base class are again not accessible in the derived class.
Given table will summarize the above three modes of inheritance and show the Base class
member access specifier when derived in all three modes of inheritance in C++:
Types of inheritance:
Single Inheritance
Multiple Inheritance
Multilevel Inheritance
Hybrid Inheritance
Hierarchical Inheritance
Single Inheritance:
When the derived class inherits only one base class, it is known as Single Inheritance.
In the above diagram, there is a Base class, and a derived class. Here the child class inherits
only one parent class.
Syntax:
OR
class A
{
... .. ...
};
class B: public A
{
... .. ...
};
#include<iostream>
using namespace std;
// base class
class Vehicle {
public:
Vehicle()
{
cout << "This is a Vehicle\n";
}
};
};
// main function
int main()
{
// Creating object of sub class will
// invoke the constructor of base classes
Car obj;
return 0;
}
Output:
This is a Vehicle
Multiple Inheritance:
Multiple Inheritance is a feature of C++ where a class can inherit from more than one class. i.e
one subclass is inherited from more than one base class.
Syntax:
Example:
#include <iostream>
using namespace std;
Output :
This is a Vehicle
This is a 4 wheeler Vehicle
Multilevel Inheritance:
In this type of inheritance, a derived class is created from another derived class.
Syntax:-
class C
{
... .. ...
};
class B:public C
{
... .. ...
};
class A: public B
{
... ... ...
};
Example:
#include <iostream>
using namespace std;
// base class
class Vehicle {
public:
Vehicle() { cout << "This is a Vehicle\n"; }
};
Output:
This is a Vehicle
Objects with 4 wheels are vehicles
Car has 4 Wheels
Hierarchical Inheritance:
In this type of inheritance, more than one subclass is inherited from a single base class. i.e. more
than one derived class is created from a single base class.
Syntax:-
class A
{
// body of the class A.
}
class B : public A
{
// body of class B.
}
class C : public A
{
// body of class C.
}
class D : public A
{
// body of class D.
}
Example:
#include <iostream>
using namespace std;
// base class
class Vehicle {
public:
Vehicle() { cout << "This is a Vehicle\n"; }
};
// first sub class
class Car : public Vehicle {
};
// main function
int main()
{
// Creating object of sub class will
// invoke the constructor of base class.
Car obj1;
Bus obj2;
return 0;
}
Output:
This is a Vehicle
This is a Vehicle
Hybrid Inheritance is implemented by combining more than one type of inheritance. For
example: Combining Hierarchical inheritance and Multiple Inheritance.
Example:
#include <iostream>
using namespace std;
// base class
class Vehicle {
public:
Vehicle() { cout << "This is a Vehicle\n"; }
};
// base class
class Fare {
public:
Fare() { cout << "Fare of Vehicle\n"; }
};
Output:
This is a Vehicle
Fare of Vehicle
Virtual function
A C++ virtual function is a member function in the base class that you redefine in a
derived class. It is declared using the virtual keyword.
It is used to tell the compiler to perform dynamic linkage or late binding on the function.
There is a necessity to use the single pointer to refer to all the objects of the different
classes. So, we create the pointer to the base class that refers to all the derived objects.
But, when base class pointer contains the address of the derived class object, always
executes the base class function. This issue can only be resolved by using the 'virtual'
function.
A 'virtual' is a keyword preceding the normal declaration of a function.
When the function is made virtual, C++ determines which function is to be invoked at the
runtime based on the type of the object pointed by the base class pointer.
By default, C++ matches a function call with the correct function definition at compile time. This
is called static binding. You can specify that the compiler match a function call with the correct
function definition at run time; this is called dynamic binding. You declare a function with the
keyword virtual if you want the compiler to use dynamic binding for that specific function.
If we have created a virtual function in the base class and it is being overridden in the derived
class then we don’t need virtual keyword in the derived class, functions are automatically
considered as virtual functions in the derived class.
class base {
public:
virtual void print()
{
cout << "print base class\n";
}
void show()
{
cout << "show base class\n";
}
};
int main()
{
base *bptr;
derived d;
bptr = &d;
return 0;
}
Output:
Example:
class base {
public:
void fun_1() { cout << "base-1\n"; }
virtual void fun_2() { cout << "base-2\n"; }
virtual void fun_3() { cout << "base-3\n"; }
virtual void fun_4() { cout << "base-4\n"; }
};
base-1
derived-2
base-3
base-4
Initially, we create a pointer of type base class and initialize it with the address of the derived
class object. When we create an object of the derived class, the compiler creates a pointer as a
data member of the class containing the address of VTABLE of the derived class.
Similar concept of Late and Early Binding is used as in above example. For fun_1() function
call, base class version of function is called, fun_2() is overridden in derived class so derived
class version is called, fun_3() is not overridden in derived class and is virtual function so base
class version is called, similarly fun_4() is not overridden so base class version is called.
fun_4(int) in derived class is different from virtual function fun_4() in base class as prototypes of
both the functions are different.
Slower: The function call takes slightly longer due to the virtual mechanism and makes it
more difficult for the compiler to optimize because it does not know exactly which function
is going to be called at compile time.
Difficult to Debug: In a complex system, virtual functions can make it a little more difficult
to figure out where a function is being called from.
Pure Virtual Function
A virtual function is not used for performing any task. It only serves as a placeholder.
When the function has no definition, such function is known as "do-nothing" function.
The "do-nothing" function is known as a pure virtual function. A pure virtual function is a
function declared in the base class that has no definition relative to the base class.
A class containing the pure virtual function cannot be used to declare the objects of its own,
such classes are known as abstract base classes.
The main objective of the base class is to provide the traits to the derived classes and to
create the base pointer used for achieving the runtime polymorphism.
Example:
#include<iostream>
using namespace std;
class B {
public:
virtual void s() = 0; // Pure Virtual Function
};
class D:public B {
public:
void s() {
cout << "Virtual Function in Derived class\n";
}
};
int main() {
B *b;
D dobj;
b = &dobj;
b->s();
}
Output:
In simple inheritance, the constructors of the base classes and constructors of the derived class
are automatically executed when an object of the derived class is created. The constructors of
the base classes are executed first and then the constructor of the derived class is executed. The
constructors of base classes are executed in the same order in which the base classes are
specified in derived class(i.e. from left to right).
Similarly, the destructors are executed in reverse order, i.e. derived class constructor is
executed first and then constructors of the base classes are executed.
Example:
#include <iostream>
using namespace std;
class Base
{
public:
Base()
{
cout<<"Constructor Base \n";
}
~Base()
{
cout<<"Destructor Base \n";
}
};
~Derived()
{
cout<<"Destructor Derived \n";
}
};
int main(void)
{
Derived d;
return 0;
}
Output:
Constructor Base
Constructor Derived
Destructor Derived
Destructor Base
During multiple inheritance, the constructor of base class will be called first.
For example if you have defined like this “class Derived: public A, public B”, then Constructor
of class A will be called, then constructor of class B will be called.
Example:
#include <iostream>
using namespace std;
class A
{
public:
A()
{
cout<<"Constructor A \n";
}
~A()
{
cout<<"Destructor A \n";
}
};
class B
{
public:
B()
{
cout<<"Constructor B \n";
}
~B()
{
cout<<"Destructor B \n";
}
};
class Derived: public A, public B
{
public:
Derived()
{
cout<<"Constructor Derived \n";
}
~Derived()
{
cout<<"Destructor Derived \n";
}
};
int main(void)
{
Derived d;
return 0;
Output:
Constructor A
Constructor B
Constructor Derived
Destructor Derived
Destructor B
Destructor A
Polymorphism
Polymorphism word is the combination of "poly," which means many + "morphs," which means
forms, which together means many forms. Polymorphism in C++ is when the behavior of the
same object or function is different in different contexts. Eg., the + operator in C++ is one of the
best examples of polymorphism. The + operator is used to add two integers as follows :
#include <bits/stdc++.h>
using namespace std;
int main() {
int a = 10;
int b = 32;
In the above example, + is used to add a = 10a=10 and b = 32b=32, the output Value of a + ba+b
is : 42.
However, + is also used to concatenate two string operands. The + operator is used to
concatenate two strings as follows :
#include <bits/stdc++.h>
using namespace std;
int main() {
string a = "poly";
string b = "morphism";
In C++, we can use two functions having the same name if they have different parameters (either
types or number of arguments).
And, depending upon the number/type of arguments, different functions are called. For example,
#include <iostream>
using namespace std;
return 0;
}
Output:
Sum 1 = 11
Sum 2 = 12.1
Sum 3 = 18
Here, we have created 3 different sum() functions with different parameters (number/type of
parameters). And, based on the arguments passed during a function call, a particular sum() is
called.
It's a compile-time polymorphism because the compiler knows which function to execute
before the program is compiled.
In C++, we can overload an operator as long as we are operating on user-defined types like
objects or structures. We cannot use operator overloading for basic types such as int, double, etc.
Operator overloading is basically function overloading, where different operator functions have
the same symbol but different operands.
And, depending on the operands, different operator functions are executed. For example,
class Count {
private:
int value;
public:
void display() {
cout << "Count: " << value << endl;
}
};
int main() {
Count count1;
count1.display();
return 0;
}
Output:
Count: 6
Here, we have overloaded the ++ operator, which operates on objects of Count class (object
count1 in this case).
We have used this overloaded operator to directly increment the value variable of count1 object
by 1.
This is also a compile-time polymorphism.
In C++ inheritance, we can have the same function in the base class as well as its derived classes.
When we call the function using an object of the derived class, the function of the derived class
is executed instead of the one in the base class.
So, different functions are executed depending on the object calling the function.
#include <iostream>
using namespace std;
class Base {
public:
virtual void print() {
cout << "Base Function" << endl;
}
};
return 0;
}
Output:
Derived Function
Here, we have used a print() function in the Base class and the same function in the Derived
class
When we call print() using the Derived object derived1, it overrides the print() function of Base
by executing the print() function of the Derived class.
It's a runtime polymorphism because the function call is not resolved by the compiler, but it is
resolved in the runtime instead.
In C++, we may not be able to override functions if we use a pointer of the base class to point to
an object of the derived class.
Using virtual functions in the base class ensures that the function can be overridden in these
cases.
Thus, virtual functions actually fall under function overriding. For example,
#include <iostream>
using namespace std;
class Base {
public:
virtual void print() {
cout << "Base Function" << endl;
}
};
return 0;
}
Output:
Derived Function
Here, we have used a virtual function print() in the Base class to ensure that it is overridden by
the function in the Derived class.
Virtual functions are runtime polymorphism.
The unary operators are one such extensively used operator. Unary Operators work on the
operations that are carried out on just one operand, both in mathematics and in programming
languages. Unary operators do not utilize two operands to calculate the result as binary operators
do.
A single operand/variable is used with the unary operator to determine the new value of that
variable. Unary operators are used with the operand is either the prefix or postfix position. Unary
operators come in a variety of forms, and they all have right-to-left associativity and equal
precedence.
These are some of examples, unary operators:
Example:
public:
Complex()
{
real = 0;
img = 0;
}
Complex(int r, int i)
{
real = r;
img = i;
}
}
There are two ways for unary operation overloading in C++, i.e.
Example: C++ program to overload unary minus (-) to negate the values.
#include<iostream>
using namespace std;
class NUM
{
private:
int n;
public:
//function to get number
void getNum(int x)
{
n=x;
}
//function to display number
void dispNum(void)
{
cout << "value of n is: " << n;
}
//unary - operator overloading
void operator - (void)
{
n=-n;
}
};
int main()
{
NUM num;
num.getNum(10);
-num;
num.dispNum();
cout << endl;
return 0;
}
Output:
An operator which contains two operands to perform a mathematical operation is called the
Binary Operator Overloading. It is a polymorphic compile technique where a single operator can
perform various functionalities by taking two operands from the programmer or user.
Example : Program to add two numbers using the binary operator overloading
#include <iostream>
using namespace std;
class Arith_num
{
// declare data member or variable
int x, y;
public:
// create a member function to take input
void input()
{
cout << " Enter the first number: ";
cin >> x;
}
void input2()
{
cout << " Enter the second number: ";
cin >> y;
}
// overloading the binary '+' operator to add number
Arith_num operator + (Arith_num &ob)
{
// create an object
Arith_num A;
// assign values to object
A.x = x + ob.x;
return (A);
}
// display the result of binary + operator
void print()
{
cout << "The sum of two numbers is: " <<x;
}
};
int main ()
{
Arith_num x1, y1, res; // here we create object of the class Arith_num i.e x1 and y1
// accepting the values
x1.input();
y1.input();
// assign result of x1 and x2 to res
res = x1 + y1;
// call the print() function to display the results
res.print();
return 0;
}
Output: