Unit 5 Notes
Unit 5 Notes
Unit-5 notes
Objects and Classes : Basics of object and class in C++, Private and public members,
static
data and function members, constructors and their types, destructors, operator
overloading,
type conversion. Inheritance : Concept of Inheritance, types of inheritance: single,
multiple,
multilevel, hierarchical, hybrid, protected members, overriding, virtual base class
Polymorphism : Pointers in C++, Pointes and Objects, this pointer, virtual and pure
virtual
functions, Implementing polymorphism
A Class is a user-defined data type that has data members and member functions.
Data members are the data variables and member functions are the functions used to
manipulate these variables together, these data members and member functions define
the properties and behavior of the objects in a Class.
In the above example of class Car, the data member will be speed limit, mileage, etc,
and member functions can be applying brakes, increasing speed, etc.
Declaring Objects
When a class is defined, only the specification for the object is defined; no memory or
storage is allocated. To use the data and access functions defined in the class, you need to
create objects.
Syntax
ClassName ObjectName;
Accessing data members and member functions: The data members and member functions
of the class can be accessed using the dot(‘.’) operator with the object. For example, if the
name of the object is obj and you want to access the member function with the name
printName() then you will have to write obj.printName().
To define a member function outside the class definition we have to use the scope
resolution:: operator along with the class name and function name.
#include <bits/stdc++.h>
using namespace std;
class Geeks
{
public:
string geekname;
int id;
Geeks obj1;
obj1.geekname = "xyz";
obj1.id=15;
// call printname()
obj1.printname();
cout << endl;
// call printid()
obj1.printid();
return 0;
}
Output
Geekname is: xyz
Geek id is: 15
Note that all the member functions defined inside the class definition are by default inline,
but you can also make any non-class function inline by using the keyword inline with them.
Inline functions are actual functions, which are copied everywhere during compilation, like
pre-processor macro, so the overhead of function calls is reduced.
Note: Declaring a friend function is a way to give private access to a non-member function.
Constructors
Constructors are special class members which are called by the compiler every time an object
of that class is instantiated. Constructors have the same name as the class and may be defined
inside or outside the class definition. There are 3 types of constructors:
Default Constructors
Parameterized Constructors
Copy Constructors
//Default Constructor
Geeks()
{
cout << "Default Constructor called" << endl;
id=-1;
}
//Parameterized Constructor
Geeks(int x)
{
cout <<"Parameterized Constructor called "<< endl;
id=x;
}
};
int main() {
A Copy Constructor creates a new object, which is an exact copy of the existing object. The
compiler provides a default Copy Constructor to all the classes.
Syntax:
Destructors
Destructor is another special member function that is called by the compiler when the scope
of the object ends.
int main()
{
Geeks obj1;
obj1.id=7;
int i = 0;
while ( i < 5 )
{
Geeks obj2;
obj2.id=i;
i++;
} // Scope for obj2 ends here
return 0;
} // Scope for obj1 ends here
Output
Destructor called for id: 0
Destructor called for id: 1
Destructor called for id: 2
Destructor called for id: 3
Many people might say that it’s a basic syntax and we should give a semicolon at the end of
the class as its rule defines in cpp. But the main reason why semi-colons are there at the end
of the class is compiler checks if the user is trying to create an instance of the class at the end
of it.
Yes just like structure and union, we can also create the instance of a class at the end just
before the semicolon. As a result, once execution reaches at that line, it creates a class and
allocates memory to your instance.
#include <iostream>
using namespace std;
class Demo{
int a, b;
public:
Demo() // default constructor
{
cout << "Default Constructor" << endl;
}
Demo(int a, int b):a(a),b(b) //parameterised constructor
{
cout << "parameterized constructor -values" << a << " "<< b <<
endl;
}
}instance;
int main() {
return 0;
}
Output
Default Constructor
We can see that we have created a class instance of Demo with the name “instance”, as a
result, the output we can see is Default Constructor is called.
Similarly, we can also call the parameterized constructor just by passing values here
#include <iostream>
using namespace std;
class Demo{
public:
int a, b;
Demo()
{
cout << "Default Constructor" << endl;
}
Demo(int a, int b):a(a),b(b)
{
cout << "parameterized Constructor values-" << a << " "<< b <<
endl;
}
}instance(100,200);
int main() {
return 0;
}
Output
parameterized Constructor values-100 200
So by creating an instance just before the semicolon, we can create the Instance of class.
1. Public
2. Private
3. Protected
Note: If we do not specify any access modifiers for the members inside the class, then by
default the access modifier for the members will be Private.
Example:
// access modifier
#include<iostream>
// class definition
class Circle
public:
double radius;
double compute_area()
return 3.14*radius*radius;
};
// main function
int main()
Circle obj;
obj.radius = 5.5;
return 0;
Output:
In the above program, the data member radius is declared as public so it could be accessed
outside the class and thus was allowed access from inside main().
2. Private: The class members declared as private can be accessed only by the member
functions inside the class. They are not allowed to be accessed directly by any object or
function outside the class. Only the member functions or the friend functions are allowed to
access the private data members of the class.
Example:
// access modifier
#include<iostream>
class Circle
private:
double radius;
public:
double compute_area()
return 3.14*radius*radius;
};
// main function
int main()
Circle obj;
obj.radius = 1.5;
return 0;
Output:
The output of the above program is a compile time error because we are not allowed to access
the private data members of a class directly from outside the class. Yet an access to obj.radius
is attempted, but radius being a private data member, we obtained the above compilation
error.
However, we can access the private data members of a class indirectly using the public
member functions of the class.
Example:
// access modifier
#include<iostream>
class Circle
private:
double radius;
public:
void compute_area(double r)
radius = r;
};
// main function
int main()
Circle obj;
obj.compute_area(1.5);
return 0;
Output:
3. Protected: The protected access modifier is similar to the private access modifier in the
sense that it can’t be accessed outside of its class unless with the help of a friend class. The
difference is that the class members declared as Protected can be accessed by any subclass
(derived class) of that class as well.
Note: This access through inheritance can alter the access modifier of the elements of base
class in derived class depending on the mode of Inheritance.
Example:
#include <bits/stdc++.h>
// base class
class Parent
protected:
int id_protected;
};
public:
id_protected = id;
void displayId()
};
// main function
int main() {
Child obj1;
obj1.setId(81);
obj1.displayId();
return 0;
Output:
id_protected is: 81
Constructors in C++
Constructor in C++ 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. It constructs the values i.e. provides data for
the object which is why it is known as a constructor.
Constructor is a member func琀椀on of a class, whose name is the same as the class name.
Constructor is a special type of member func琀椀on that is used to ini琀椀alize the data members
for an object of a class automa琀椀cally when an object of the same class is created.
Constructor is invoked at the 琀椀me of object crea琀椀on. It constructs the values i.e. provides
data for the object that is why it is known as a constructor.
Constructors do not return value, hence they do not have a return type.
A constructor gets called automa琀椀cally when we create the object of the class.
<class-name> (list-of-parameters);
The constructor can be defined inside the class declaration or outside the class declaration
#include <iostream>
class student {
int rno;
char name[50];
double fee;
public:
// constructor
student()
void display()
cout << endl << rno << "\t" << name << "\t" << fee;
};
int main()
s.display();
return 0;
Output
#include <iostream>
class student {
int rno;
char name[50];
double fee;
public:
student();
void display();
};
student::student()
void student::display()
cout << endl << rno << "\t" << name << "\t" << fee;
// driver code
int main()
student s;
s.display();
return 0;
Output
Note: We can make the constructor defined outside the class as inline to make it equivalent
to the in class definition. But note that inline is not an instruction to the compiler, it is only
the request which compiler may or may not implement depending on the circumtances.
Constructors are mostly declared in the public sec琀椀on of the class though they can be
declared in the private sec琀椀on of the class.
Constructors do not return values; hence they do not have a return type.
A constructor gets called automa琀椀cally when we create the object of the class.
The constructor makes implicit calls to new and delete operators during memory alloca琀椀on.
1. Default Constructor
2. Parameterized Constructor
3. Copy Constructor
4. Move Constructor
Let us understand the types of constructors in C++ by taking a real-world example. Suppose
you went to a shop to buy a marker. When you want to buy a marker, what are the options?
The first one you go to a shop and say give me a marker. So just saying give me a marker
means that you did not set which brand name and which color, you didn’t mention anything
just say you want a marker. So when we said just I want a marker whatever the frequently
sold marker is there in the market or his shop he will simply hand over that. And this is what
a default constructor is!
The second method is you go to a shop and say I want a marker red in color and XYZ brand.
So you are mentioning this and he will give you that marker. So in this case you have given
the parameters. And this is what a parameterized constructor is!
Then the third one you go to a shop and say I want a marker like this(a physical marker on
your hand). So the shopkeeper will see that marker. Okay, and he will give a new marker for
you. So copy of that marker. And that’s what a copy constructor is!
Now, assume that you don’t to buy a new marker but instead take ownership of your friend’s
marker. It means taking ownership of already present resources instead of getting a new one.
That’s what a move constructor is!
The below examples demonstrate how to use the default constructors in C++.
Example 1:
// constructors
#include <iostream>
class construct {
public:
int a, b;
// Default Constructor
construct()
a = 10;
b = 20;
};
int main()
construct c;
cout << "a: " << c.a << endl << "b: " << c.b;
return 1;
Output
a: 10
b: 20
Note: Even if we do not define any constructor explicitly, the compiler will automatically
provide a default constructor implicitly.
Example 2:
// constructor
#include <iostream>
// class
class student {
int rno;
char name[50];
double fee;
public:
};
int main()
student s;
return 0;
Output
(no output)
As we can see, we are able the object of class student is created without passing any
argument even when we haven’t defined any explicit default constructor for it.
The below examples demonstrate how to use the parameterized constructors in C++.
#include <iostream>
class Point {
private:
int x, y;
public:
// Parameterized Constructor
x = x1;
y = y1;
};
int main()
// Constructor called
return 0;
Output
p1.x = 10, p1.y = 15
#include <iostream>
#include <string.h>
// class definition
class student {
int rno;
char name[50];
double fee;
public:
void display();
};
rno = no;
strcpy(name, n);
fee = f;
void student::display()
cout << endl << rno << "\t" << name << "\t" << fee;
// driver code
int main()
s.display();
return 0;
Output
1001 Ram 10000
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 parameterized constructors can be called explicitly or implicitly:
Student s;
Example 3:
// parameterized constructor
#include <iostream>
#include <string.h>
// class definition
class student {
int rno;
char name[50];
double fee;
public:
rno = no;
strcpy(name, n);
fee = f;
};
// driver code
int main()
return 0;
Output
It is used to ini琀椀alize the various data elements of di昀昀erent objects with di昀昀erent values
when they are created.
Just like normal functions, we can also define default values for the arguments of
parameterized constructors. All the rules of the default arguments will be applied to these
parameters.
#include <iostream>
// class
class GFG {
private:
int data;
public:
GFG(int x = 0) { data = x; }
};
int main()
GFG obj2(25);
cout << "First Object Data: " << obj1.getData() << endl;
<< endl;
return 0;
Output
First Object Data: 0
Second Object Data: 25
As we can see, when the default values are assigned to every argument of the parameterized
constructor, it is legal to create the object without passing any parameters just like default
constructors. So, this type of constructor works as both a default and parameterized
constructor.
Just like the default constructor, the C++ compiler also provides an implicit copy
constructor if the explicit copy constructor definition is not present. Here, it is to be
noted that, unlike the default constructor where the presence of any type of explicit
constructor results in the deletion of the implicit default constructor, the implicit copy
constructor will always be created by the compiler if there is no explicit copy constructor or
explicit move constructor is present.
The below examples demonstrate how to use the copy constructors in C++.
// constructor
#include <iostream>
class Sample {
int id;
public:
// parameterized constructor
Sample(int x) { id = x; }
};
int main()
Sample obj1(10);
obj1.display();
obj2.display();
return 0;
Output
ID=10
ID=10
// copy constructor
#include <iostream>
class Sample {
int id;
public:
Sample() {}
// parameterized constructor
Sample(int x) { id = x; }
// copy constructor
Sample(Sample& t) { id = t.id; }
};
// driver code
int main()
Sample obj1(10);
obj1.display();
obj2.display();
return 0;
Output
ID=10
ID=10
// parameterized constructor
#include <iostream>
#include <string.h>
// class definition
class student {
int rno;
char name[50];
double fee;
public:
rno = t.rno;
strcpy(name, t.name);
fee = t.fee;
void display();
};
rno = no;
strcpy(name, n);
fee = f;
void student::display()
cout << endl << rno << "\t" << name << "\t" << fee;
int main()
s.display();
manjeet.display();
return 0;
Output
1001 Manjeet 10000
1001 Manjeet 10000
The move constructor takes the rvalue reference of the object of the same class and transfers
the ownership of this object to the newly created object.
Like a copy constructor, the compiler will create a move constructor for each class that does
not have any explicit move constructor.
The below examples demonstrate how to use the move constructors in C++.
// constructor
#include <iostream>
class Box {
public:
// Constructor
Box(int value)
*data = value;
// Move constructor
// data
// double deletion
// Destructor
};
int main()
Box originalBox(42);
// originalBox
Box newBox(move(originalBox));
return 0;
Output
Move Constructor Called
newBox.data: 42
You can de昀椀ne your own move constructor to handle speci昀椀c resource transfers.
Destructors in C++
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.
Like constructors, destructors can also be defined either inside or outside of the class.
~ <class-name>(){}
<class-name>: : ~<class-name>(){}
#include <iostream>
class Test {
public:
};
main()
Test t;
return 0;
Output
Constructor executed
Destructor executed
// destroyed
#include <iostream>
int count = 0;
// class definition
class Test {
public:
Test()
count++;
cout << "No. of Object created: " << count << endl;
~Test()
<< endl;
--count;
};
// driver code
int main()
return 0;
Output
Destructor is invoked automa琀椀cally by the compiler when its corresponding constructor goes
out of scope and releases the memory space that is no longer required by the program.
Destructor neither requires any argument nor returns any value therefore it cannot be
overloaded.
Only one copy of that member is created for the en琀椀re class and is shared by all the objects
of that class, no ma琀琀er how many objects are created.
It is ini琀椀alized before any object of this class is created, even before the main starts.
It is visible only within the class, but its life琀椀me is the en琀椀re program.
Syntax:
Below is the C++ program to demonstrate the working of static data members:
#include <iostream>
class A {
public:
A()
endl;
};
class B {
static A a;
public:
B()
endl;
};
// Driver code
int main()
B b;
return 0;
Output
B's Constructor Called
Explanation: The above program calls only B’s constructor, it doesn’t call A’s
constructor. The reason is,
Static members are only declared in a class declaration, not defined. They must be explicitly
defined outside the class using the scope resolution operator.
Below is the C++ program to show when static member ‘a’ is accessed without explicit
definition:
#include <iostream>
class A {
int x;
public:
A()
endl;
};
class B {
static A a;
public:
B()
endl;
static A getA()
return a;
};
// Driver code
int main()
B b;
A a = b.getA();
return 0;
Output
Explanation: Here static member ‘a’ is accessed without explicit definition. If we add the
definition, the program will work fine and call A’s constructor.
Below is the C++ program to show how to resolve the above error:
#include <iostream>
class A {
int x;
public:
A()
endl;
};
class B {
static A a;
public:
B()
endl;
static A getA()
return a;
};
// Definition of a
A B::a;
// Driver code
int main()
A a = b1.getA();
return 0;
Output
A's constructor called
B's constructor called
B's constructor called
B's constructor called
Explanation: The above program calls B’s constructor 3 times for 3 objects (b1, b2, and b3),
but calls A’s constructor only once. The reason is that the static members are shared among
all objects. That is why they are also known as class members or class fields.
NOTE: Static data members can only be defined globally in C++. The only exception to this
are static const data members of integral type which can be initialized in the class declaration.
Below is the C++ program to show access to the static member without an object:
#include <iostream>
class A {
int x;
public:
A()
endl;
};
class B {
static A a;
public:
B()
endl;
static A getA()
return a;
};
// Definition of a
A B::a;
// Driver code
int main()
A a = B::getA();
return 0;
Output
A's constructor called
Example:
class Person{
static int index_number;
};
Once a static member is declared it will be treated as same for all the objects associated with
the class.
Example:
#include <iostream>
class Student {
public:
// static member
// Constructor called
Student() { total += 1; }
};
int Student::total = 0;
int main()
// Student 1 declared
Student s1;
// Student 2 declared
Student s2;
// Student 3 declared
Student s3;
return 0;
Output
Number of students:1
Number of students:2
Number of students:3
A sta琀椀c member func琀椀on can access sta琀椀c data members and sta琀椀c member func琀椀ons
inside or outside of the class.
Sta琀椀c member func琀椀ons have a scope inside the class and cannot access the current object
pointer.
You can also use a sta琀椀c member func琀椀on to determine how many objects of the class have
been created.
Sta琀椀c members are frequently used to store informa琀椀on that is shared by all objects in a
class.
For instance, you may keep track of the quan琀椀ty of newly generated objects of a speci昀椀c
class type using a sta琀椀c data member as a counter. This sta琀椀c data member can be
increased each 琀椀me an object is generated to keep track of the overall number of objects.
Example:
#include <iostream>
class Box
private:
public:
cout << "The value of the length is: " << length << endl;
cout << "The value of the breadth is: " << breadth << endl;
cout << "The value of the height is: " << height << endl;
};
// Driver Code
int main()
Box b;
cout << "Static member function is called through Object name: \n" <<
endl;
b.print();
cout << "\nStatic member function is called through Class name: \n" <<
endl;
Box::print();
return 0;
Output
Static member function is called through Object name:
Inheritance in C++
The capability of a class to derive properties and characteristics from another class is called
Inheritance. Inheritance is one of the most important features of Object-Oriented
Programming.
Inheritance is a feature or a process in which, new classes are created from the existing
classes. The new class created is called “derived class” or “child class” and the existing class
is known as the “base class” or “parent class”. The derived class now is said to be inherited
from the base class.
When we say derived class inherits the base class, it means, the derived class inherits all the
properties of the base class, without changing the properties of base class and may add new
features to its own. These new features in the derived class will not affect the base class. The
derived class is the specialized class for the base class.
Sub Class: The class that inherits proper琀椀es from another class is called Subclass or Derived
Class.
Super Class: The class whose proper琀椀es are inherited by a subclass is called Base Class or
Superclass.
Modes of Inheritance
Types of Inheritance
Consider a group of vehicles. You need to create classes for Bus, Car, and Truck. The
methods fuelAmount(), capacity(), applyBrakes() will be the same for all three classes. If we
create these classes avoiding inheritance then we have to write all of these functions in each
of the three classes as shown below figure:
You can clearly see that the above process results in duplication of the same code 3 times.
This increases the chances of error and data redundancy. To avoid this type of situation,
inheritance is used. If we create a class Vehicle and write these three functions in it and
inherit the rest of the classes from the vehicle class, then we can simply avoid the duplication
of data and increase re-usability. Look at the below diagram in which the three classes are
inherited from vehicle class:
Using inheritance, we have to write the functions only one time instead of three times as we
have inherited the rest of the three classes from the base class (Vehicle).
Implementing inheritance in C++: For creating a sub-class that is inherited from the base
class we have to follow the below syntax.
Derived Classes: A Derived class is defined as the class derived from the base class.
Syntax:
Where
class — keyword to create a new class
derived_class_name — name of the new class, which will inherit the base class
access-specifier — either of private, public or protected. If neither is specified, PRIVATE is
taken as default
base-class-name — name of the base class
Note: A derived class doesn’t inherit access to private data members. However, it does
inherit a full parent object, which contains any private members which that class declares.
Example:
1. class ABC : private XYZ //private derivation
{ }
2. class ABC : public XYZ //public derivation
{ }
3. class ABC : protected XYZ //protected derivation
{ }
4. class ABC: XYZ //private derivation by default
{ }
Note:
o When a base class is privately inherited by the derived class, public members of the base
class becomes the private members of the derived class and therefore, the public members of
the base class can only be accessed by the member functions of the derived class. They are
inaccessible to the objects of the derived class.
o On the other hand, when the base class is publicly inherited by the derived class, public
members of the base class also become the public members of the derived class. Therefore,
the public members of the base class are accessible by the objects of the derived class as well
as by the member functions of the derived class.
#include <iostream>
using namespace std;
class Person {
int id;
char name[100];
public:
void set_p()
{
cout << "Enter the Id:";
cin >> id;
cout << "Enter the Name:";
cin >> name;
}
void display_p()
{
cout << endl <<"Id: "<< id << "\nName: " << name <<endl;
}
};
public:
void set_s()
{
set_p();
cout << "Enter the Course Name:";
cin >> course;
cout << "Enter the Course Fee:";
cin >> fee;
}
void display_s()
{
display_p();
cout <<"Course: "<< course << "\nFee: " << fee << endl;
}
};
int main()
{
Student s;
s.set_s();
s.display_s();
return 0;
}
Output:
Id: 101
Name: Dev
Course: GCS
Fee: 70000
// Example: define member function without argument outside the class
#include<iostream>
using namespace std;
class Person
{
int id;
char name[100];
public:
void set_p();
void display_p();
};
void Person::set_p()
{
cout<<"Enter the Id:";
cin>>id;
cout<<"Enter the Name:";
cin>>name;
}
void Person::display_p()
{
cout<<endl<<"id: "<< id<<"\nName: "<<name;
}
public:
void set_s();
void display_s();
};
void Student::set_s()
{
set_p();
cout<<"Enter the Course Name:";
cin>>course;
cout<<"Enter the Course Fee:";
cin>>fee;
}
void Student::display_s()
{
display_p();
cout<<"\nCourse: "<<course<<"\nFee: "<<fee<<endl;
}
int main()
{
Student s;
s.set_s();
s.display_s();
return 0;
}
Output:
#include<iostream>
#include<string.h>
using namespace std;
class Person
{
int id;
char name[100];
public:
void set_p(int,char[]);
void display_p();
};
void Person::display_p()
{
cout<<endl<<id<<"\t"<<name;
}
void Student::display_s()
{
display_p();
cout<<"t"<<course<<"\t"<<fee;
}
main()
{
Student s;
s.set_s(1001,"Ram","B.Tech",2000);
s.display_s();
return 0;
}
#include <bits/stdc++.h>
using namespace std;
// Base class
class Parent {
public:
int id_p;
};
// main function
int main()
{
Child obj1;
return 0;
}
Output
Child id is: 7
Parent id is: 91
Output:
Child id is: 7
Parent id is: 91
In the above program, the ‘Child’ class is publicly inherited from the ‘Parent’ class so the
public data members of the class ‘Parent’ will also be inherited by the class ‘Child’.
Modes of Inheritance: There are 3 modes of inheritance.
1. Public Mode: If we derive a subclass from a public base class. Then the public
member of the base class will become public in the derived class and protected
members of the base class will become protected in the derived class.
2. Protected Mode: If we derive a subclass from a Protected base class. Then both
public members and protected members of the base class will become protected in the
derived class.
3. Private Mode: If we derive a subclass from a Private base class. Then both public
members and protected members of the base class will become Private in the derived
class.
Note: The private members in the base class cannot be directly accessed in the derived class,
while protected members can be directly accessed. For example, Classes B, C, and D all
contain the variables x, y, and z in the below example. It is just a question of access.
protected:
int y;
private:
int z;
};
class B : public A {
// x is public
// y is protected
// z is not accessible from B
};
class C : protected A {
// x is protected
// y is protected
// z is not accessible from C
};
The below table summarizes the above three modes and shows the access specifier of the
members of the base class in the subclass when derived in public, protected and private
modes:
The below table summarizes the above three modes and shows the access specifier of the
members of the base class in the subclass when derived in public, protected and private
modes:
Types Of Inheritance:-
1. Single inheritance
2. Mul琀椀level inheritance
3. Mul琀椀ple inheritance
4. Hierarchical inheritance
5. Hybrid inheritance
1. Single Inheritance: In single inheritance, a class is allowed to inherit from only one class.
i.e. one subclass is inherited by one base class only.
Syntax:
// Single inheritance
#include<iostream>
// base class
class Vehicle {
public:
Vehicle()
};
};
// main function
int main()
Car obj;
return 0;
Output
This is a Vehicle
// Example:
#include<iostream>
class A
protected:
int a;
public:
void set_A()
cin>>a;
void disp_A()
cout<<endl<<"Value of A="<<a;
};
class B: public A
int b,p;
public:
void set_B()
set_A();
cin>>b;
void disp_B()
disp_A();
cout<<endl<<"Value of B="<<b;
void cal_product()
p=a*b;
};
main()
B _b;
_b.set_B();
_b.cal_product();
return 0;
// Example:
#include<iostream>
class A
protected:
int a;
public:
void set_A(int x)
a=x;
void disp_A()
cout<<endl<<"Value of A="<<a;
};
class B: public A
int b,p;
public:
set_A(x);
b=y;
void disp_B()
disp_A();
cout<<endl<<"Value of B="<<b;
void cal_product()
p=a*b;
};
main()
B _b;
_b.set_B(4,5);
_b.cal_product();
return 0;
Output
Product of 4 * 5 = 20
2. 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:
Here, the number of base classes will be separated by a comma (‘, ‘) and the access mode for
every base class must be specified.
// multiple inheritance
#include <iostream>
class Vehicle {
public:
};
class FourWheeler {
public:
FourWheeler()
};
};
// main function
int main()
Car obj;
return 0;
Output
This is a Vehicle
This is a 4 wheeler Vehicle
// Example:
#include<iostream>
class A
protected:
int a;
public:
void set_A()
cin>>a;
void disp_A()
cout<<endl<<"Value of A="<<a;
};
class B: public A
protected:
int b;
public:
void set_B()
cin>>b;
void disp_B()
cout<<endl<<"Value of B="<<b;
};
class C: public B
int c,p;
public:
void set_C()
cin>>c;
void disp_C()
cout<<endl<<"Value of C="<<c;
void cal_product()
p=a*b*c;
};
main()
C _c;
_c.set_A();
_c.set_B();
_c.set_C();
_c.disp_A();
_c.disp_B();
_c.disp_C();
_c.cal_product();
return 0;
To know more about it, please refer to the article Multiple Inheritances.
3. 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
{
... ... ...
};
// C++ program to implement
// Multilevel Inheritance
#include <iostream>
// base class
class Vehicle {
public:
};
public:
fourWheeler()
};
public:
};
// main function
int main()
Car obj;
return 0;
Output
This is a Vehicle
Objects with 4 wheels are vehicles
Car has 4 Wheels
4. 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.
}
// C++ program to implement
// Hierarchical Inheritance
#include <iostream>
// base class
class Vehicle {
public:
};
};
};
// main function
int main()
Car obj1;
Bus obj2;
return 0;
Output
This is a Vehicle
This is a Vehicle
#include <iostream>
// base class
class Vehicle {
public:
};
// base class
class Fare {
public:
};
};
};
// main function
int main()
Bus obj2;
return 0;
Output
This is a Vehicle
Fare of Vehicle
// Example:
#include <iostream>
class A
protected:
int a;
public:
void get_a()
cin>>a;
};
class B : public A
protected:
int b;
public:
void get_b()
cin>>b;
};
class C
protected:
int c;
public:
void get_c()
cin>>c;
};
protected:
int d;
public:
void mul()
get_a();
get_b();
get_c();
};
int main()
D d;
d.mul();
return 0;
// Inheritance
#include <iostream>
class ClassA {
public:
int a;
};
public:
int b;
};
public:
int c;
};
public:
int d;
};
int main()
ClassD obj;
obj.b = 20;
obj.c = 30;
obj.d = 40;
Output
a from ClassB : 10
a from ClassC : 100
b : 20
c : 30
d : 40
Output:
a from ClassB : 10
a from ClassC : 100
b : 20
c : 30
d : 40
In the above example, both ClassB and ClassC inherit ClassA, they both have a single copy
of ClassA. However Class-D inherits both ClassB and ClassC, therefore Class-D has two
copies of ClassA, one from ClassB and another from ClassC.
If we need to access the data member of ClassA through the object of Class-D, we must
specify the path from which a will be accessed, whether it is from ClassB or ClassC, bcoz
compiler can’t differentiate between two copies of ClassA in Class-D.
1) Avoiding ambiguity using the scope resolution operator: Using the scope resolution
operator we can manually specify the path from which data member a will be accessed, as
shown in statements 3 and 4, in the above example.
#include<iostream>
class ClassA
public:
int a;
};
public:
int b;
};
public:
int c;
};
public:
int d;
};
int main()
ClassD obj;
obj.b = 20;
obj.c = 30;
obj.d = 40;
Output:
a : 100
b : 20
c : 30
d : 40
According to the above example, Class-D has only one copy of ClassA, therefore, statement
4 will overwrite the value of a, given in statement 3.
In this article, we will further discuss about operator overloading in C++ with examples and
see which operators we can or cannot overload in C++.
Example:
int a;
float b,sum;
sum = a + b;
Here, variables “a” and “b” are of types “int” and “float”, which are built-in data types.
Hence the addition operator ‘+’ can easily add the contents of “a” and “b”. This is because
the addition operator “+” is predefined to add variables of built-in data type only.
Implementation:
// Overloading
class A {
statements;
};
int main()
a3 = a1 + a2;
return 0;
In this example, we have 3 variables “a1”, “a2” and “a3” of type “class A”. Here we are
trying to add two objects “a1” and “a2”, which are of user-defined type i.e. of type “class A”
using the “+” operator. This is not allowed, because the addition operator “+” is predefined to
operate only on built-in data types. But here, “class A” is a user-defined type, so the compiler
generates an error. This is where the concept of “Operator overloading” comes in.
Now, if the user wants to make the operator “+” add two class objects, the user has to
redefine the meaning of the “+” operator such that it adds two class objects. This is done by
using the concept of “Operator overloading”. So the main idea behind “Operator
overloading” is to use C++ operators with class variables or class objects. Redefining the
meaning of operators really does not change their original meaning; instead, they have been
given additional meaning along with their existing ones.
// Operator Overloading
#include <iostream>
class Complex {
private:
public:
Complex(int r = 0, int i = 0)
real = r;
imag = i;
Complex res;
return res;
void print() { cout << real << " + i" << imag << '\n'; }
};
int main()
Complex c3 = c1 + c2;
c3.print();
Output
12 + i9
Example
#include <iostream>
class Complex {
private:
public:
Complex(int r = 0, int i = 0)
real = r;
imag = i;
void print() { cout << real << " + i" << imag << endl; }
};
int main()
Complex c3
= c1
c3.print();
return 0;
Output
12 + i9
sizeof
typeid
Scope resolution (::)
Class member access operators (.(dot), .* (pointer to member operator))
Ternary or conditional (?:)
Unary operators
Binary operators
Special operators ( [ ], (), etc)
But, among them, there are some operators that cannot be overloaded. They are
Condi琀椀onal operator (?
Sizeof operator sizeof()
Binary Arithme琀椀c +, -, *, /, %
De-referencing (->)
Subscript []
Func琀椀on call ()
Logical &, | |, !
This returns the size of the object or datatype entered as the operand. This is evaluated by the
compiler and cannot be evaluated during runtime. The proper incrementing of a pointer in an
array of objects relies on the sizeof operator implicitly. Altering its meaning using
overloading would cause a fundamental part of the language to collapse.
2. typeid Operator
This provides a CPP program with the ability to recover the actually derived type of the
object referred to by a pointer or reference. For this operator, the whole point is to uniquely
identify a type. If we want to make a user-defined type ‘look’ like another type,
polymorphism can be used but the meaning of the typeid operator must remain unaltered, or
else serious issues could arise.
This helps identify and specify the context to which an identifier refers by specifying a
namespace. It is completely evaluated at runtime and works on names rather than values. The
operands of scope resolution are note expressions with data types and CPP has no syntax for
capturing them if it were overloaded. So it is syntactically impossible to overload this
operator.
The importance and implicit use of class member access operators can be understood through
the following example:
Example:
#include <iostream>
class ComplexNumber {
private:
int real;
int imaginary;
public:
this->real = real;
this->imaginary = imaginary;
void print() { cout << real << " + i" << imaginary; }
return c3;
};
int main()
ComplexNumber c3 = c1 + c2;
c3.print();
return 0;
Output
5 + i9
Explanation:
Besides, these operators also work on names and not values and there is no provision
(syntactically) to overload them.
A function overloading the ternary operator for a class say ABC using the definition
would not be able to guarantee that only one of the expressions was evaluated. Thus, the
ternary operator cannot be overloaded.
3) Conversion Operator: We can also write conversion operators that can be used to convert
one type to another type.
Example:
// of conversion operator
#include <iostream>
class Fraction {
private:
public:
Fraction(int n, int d)
num = n;
den = d;
};
int main()
float val = f;
return 0;
Output
0.4
Overloaded conversion operators must be a member method. Other operators can either be
the member method or the global method.
4) Any constructor that can be called with a single argument works as a conversion
constructor, which means it can also be used for implicit conversion to the class being
constructed.
Example:
#include <iostream>
class Point {
private:
int x, y;
public:
Point(int i = 0, int j = 0)
x = i;
y = j;
void print()
cout << "x = " << x << ", y = " << y << '\n';
};
int main()
t.print();
t.print();
return 0;
Output
x = 20, y = 20
x = 30, y = 0
All the class members declared under public will be available to everyone. The data members
and member functions declared public can be accessed by other classes too. The public
members of a class can be accessed from anywhere in the program using the direct member
access operator (.) with the object of that class.
Example:
// access modifier
#include <iostream>
// class definition
class Circle {
public:
double radius;
double compute_area()
};
// main function
int main()
Circle obj;
obj.radius = 5.5;
return 0;
Output:
Radius is: 5.5
Area is: 94.985
In the above program, the data member radius is public so we are allowed to access it outside
the class.
Protected
Protected access modifier is similar to that of private access modifiers, the difference is that
the class member declared as Protected are inaccessible outside the class but they can be
accessed by any subclass(derived class) of that class.
Example:
#include <bits/stdc++.h>
// base class
class Parent {
protected:
int id_protected;
};
public:
id_protected = id;
void displayId()
};
// main function
int main()
Child obj1;
obj1.setId(81);
obj1.displayId();
return 0;
Public Protected
All the class members declared under Protected access modi昀椀er is similar to that of private access
public will be available to everyone. modi昀椀ers.
The data members and member The class member declared as Protected are inaccessible
func琀椀ons declared public can be outside the class but they can be accessed by any
accessed by other classes too. subclass(derived class) of that class.
Another Development real-life example could be the relationship between RBI(The Reserve
Bank of India) and Other state banks like SBI, PNB, ICICI, etc. Where the RBI passes the
same regulatory function and others follow it as it is.
Function Overriding
Syntax:
class Parent{
access_modifier:
// overridden function
return_type name_of_the_function(){}
};
access_modifier:
// overriding function
return_type name_of_the_function(){}
};
Example:
#include <iostream>
class Parent {
public:
void GeeksforGeeks_Print()
};
public:
void GeeksforGeeks_Print()
};
int main()
Child Child_Derived;
Child_Derived.GeeksforGeeks_Print();
return 0;
Output
Derived Function
#include <iostream>
class Parent {
public:
void GeeksforGeeks_Print()
};
public:
void GeeksforGeeks_Print()
Parent::GeeksforGeeks_Print();
};
int main()
Child Child_Derived;
Child_Derived.GeeksforGeeks_Print();
return 0;
Output
Derived Function
Base Function
#include <iostream>
class Parent {
public:
void GeeksforGeeks()
};
public:
void GeeksforGeeks()
};
int main()
Child Child_Derived;
ptr->GeeksforGeeks();
return 0;
Output
Base Function
#include <iostream>
class Parent {
public:
void GeeksforGeeks()
};
public:
void GeeksforGeeks()
};
int main()
Child Child_Derived;
Child_Derived.GeeksforGeeks();
Child_Derived.Parent::GeeksforGeeks();
return 0;
Output
Derived Function
Base Function
#include <iostream>
class Parent
public:
void GeeksforGeeks_Print()
};
public:
void GeeksforGeeks_Print()
};
int main()
GFG1.GeeksforGeeks_Print();
GFG2.Parent::GeeksforGeeks_Print();
return 0;
Output
I am the Child class function
I am the Parent class function
A func琀椀on can be overloaded mul琀椀ple 琀椀mes as it A func琀椀on cannot be overridden mul琀椀ple 琀椀mes
is resolved at Compile 琀椀me as it is resolved at Run 琀椀me
Need for Virtual Base Classes: Consider the situation where we have one class A . This
class A is inherited by two other classes B and C. Both these class are inherited into another
in a new class D as shown in figure below.
As we can see from the figure that data members/function of class A are inherited twice to
class D. One through class B and second through class C. When any data / function member
of class A is accessed by an object of class D, ambiguity arises as to which data/function
member would be called? One inherited through B or the other inherited through C. This
confuses compiler and it displays error.
#include <iostream>
class A {
public:
void show()
};
class B : public A {
};
class C : public A {
};
};
int main()
D object;
object.show();
Compile Errors:
Syntax 1:
class B : virtual public A
{
};
Syntax 2:
class C : public virtual A
{
};
Note:
virtual can be written before or after the public. Now only one copy of data/function
member will be copied to class C and class B and class A becomes the virtual base class.
Virtual base classes offer a way to save space and avoid ambiguities in class hierarchies that
use multiple inheritances. When a base class is specified as a virtual base, it can act as an
indirect base more than once without duplication of its data members. A single copy of its
data members is shared by all the base classes that use virtual base.
Example 1
#include <iostream>
class A {
public:
int a;
A() // constructor
a = 10;
};
};
};
};
int main()
return 0;
Output
a = 10
Explanation :
The class A has just one data member a which is public. This class is virtually inherited in
class B and class C. Now class B and class C use the virtual base class A and no duplication
of data member a is done; Classes B and C share a single copy of the members in the virtual
base class A.
Example 2:
#include <iostream>
class A {
public:
void show()
};
};
};
};
int main()
D object;
object.show();
Output
Hello from A
A virtual func琀椀on is a member func琀椀on of A pure virtual func琀椀on is a member func琀椀on of base
base class which can be rede昀椀ned by derived class whose only declara琀椀on is provided in base class
class. and should be de昀椀ned in derived class otherwise
Classes having virtual func琀椀ons are not Base class containing pure virtual func琀椀on becomes
abstract. abstract.
Syntax:
virtual<func_type><func_name>() Syntax:
{ virtual<func_type><func_name>()
// code = 0;
Base class having virtual func琀椀on can be Base class having pure virtual func琀椀on becomes
instan琀椀ated i.e. its object can be made. abstract i.e. it cannot be instan琀椀ated.
If derived class do not rede昀椀ne virtual If derived class do not rede昀椀ne virtual func琀椀on of
func琀椀on of base class, then it does not a昀昀ect base class, then no compila琀椀on error but derived
compila琀椀on. class also becomes abstract just like the base class.
C++ Polymorphism
The word “polymorphism” means having many forms. In simple words, we can define
polymorphism as the ability of a message to be displayed in more than one form. A real-life
example of polymorphism is a person who at the same time can have different characteristics.
A man at the same time is a father, a husband, and an employee. So the same person exhibits
different behavior in different situations. This is called polymorphism. Polymorphism is
considered one of the important features of Object-Oriented Programming.
Types of Polymorphism
Compile-琀椀me Polymorphism
Run琀椀me Polymorphism
Types of Polymorphism
1. Compile-Time Polymorphism
This type of polymorphism is achieved by function overloading or operator overloading.
A. Function Overloading
When there are multiple functions with the same name but different parameters, then the
functions are said to be overloaded, hence this is known as Function Overloading. Functions
can be overloaded by changing the number of arguments or/and changing the type of
arguments. In simple terms, it is a feature of object-oriented programming providing many
functions that have the same name but distinct parameters when numerous tasks are listed
under one function name. There are certain Rules of Function Overloading that should be
followed while overloading a function.
// function overloading or
// Compile-time Polymorphism
#include <bits/stdc++.h>
class Geeks {
public:
void func(int x)
// 1 double parameter
void func(double x)
// 2 int parameters
cout << "value of x and y is " << x << ", " << y
<< endl;
};
// Driver code
int main()
Geeks obj1;
obj1.func(7);
obj1.func(9.132);
obj1.func(85, 64);
return 0;
Output
value of x is 7
value of x is 9.132
value of x and y is 85, 64
Explanation: In the above example, a single function named function func() acts differently
in three different situations, which is a property of polymorphism. To know more about this,
you can refer to the article – Function Overloading in C++.
B. Operator Overloading
C++ has the ability to provide the operators with a special meaning for a data type, this
ability is known as operator overloading. For example, we can make use of the addition
operator (+) for string class to concatenate two strings. We know that the task of this operator
is to add two operands. So a single operator ‘+’, when placed between integer operands, adds
them and when placed between string operands, concatenates them.
// Operator Overloading or
// Compile-Time Polymorphism
#include <iostream>
class Complex {
private:
public:
Complex(int r = 0, int i = 0)
real = r;
imag = i;
Complex res;
return res;
void print() { cout << real << " + i" << imag << endl; }
};
// Driver code
int main()
Complex c3 = c1 + c2;
c3.print();
Output
12 + i9
Explanation: In the above example, the operator ‘+’ is overloaded. Usually, this operator is
used to add two numbers (integers or floating point numbers), but here the operator is made
to perform the addition of two imaginary or complex numbers. To know more about this one,
refer to the article – Operator Overloading.
2. Runtime Polymorphism
This type of polymorphism is achieved by Function Overriding. Late binding and dynamic
polymorphism are other names for runtime polymorphism. The function call is resolved at
A. Function Overriding
Function Overriding occurs when a derived class has a definition for one of the member
functions of the base class. That base function is said to be overridden.
Runtime Polymorphism cannot be achieved by data members in C++. Let’s see an example
where we are accessing the field by reference variable of parent class which refers to the
instance of the derived class.
#include <bits/stdc++.h>
class Animal {
public:
};
public:
};
// Driver code
int main(void)
Output
Black
We can see that the parent class reference will always refer to the data member of the parent
class.
B. Virtual Function
A virtual function is a member function that is declared in the base class using the keyword
virtual and is re-defined (Overridden) in the derived class.
They are de昀椀ned by inser琀椀ng the keyword “virtual” inside a base class and are always
declared with a base class and overridden in a child class
#include <iostream>
class GFG_Base {
public:
// virtual function
<< "\n\n";
void print()
<< "\n\n";
};
public:
void display()
<< "\n\n";
void print()
<< "\n\n";
};
// Driver code
int main()
GFG_Base* base;
GFG_Child child;
base = &child;
base->GFG_Base::display();
base->print();
Output
Example 2:
#include <bits/stdc++.h>
class base {
public:
};
public:
};
// Driver code
int main()
base* bptr;
derived d;
bptr = &d;
bptr->print();
// at compile time
bptr->show();
return 0;
Output
print derived class
show base class
6. Example : Example :
The class bike can be inherit from the The class bike can have method
C++ Pointers
Pointers are symbolic representations of addresses. They enable programs to simulate call-by-
reference as well as to create and manipulate dynamic data structures. Iterating over elements
in arrays or other data structures is one of the main use of pointers.
The address of the variable you’re working with is assigned to the pointer variable that points
to the same data type (such as an int or string).
Syntax:
datatype *var_name;
int *ptr; // ptr can point to an address which holds int data
Assigning the address of a variable to a pointer using the unary operator (&) which returns
the address of that variable.
Accessing the value stored in the address using unary operator (*) which returns the value of
the variable located at the address speci昀椀ed by its operand.
The reason we associate data type with a pointer is that it knows how many bytes the data
is stored in. When we increment a pointer, we increase the pointer by the size of the data
type to which it points.
#include <bits/stdc++.h>
using namespace std;
void geeks()
{
int var = 20;
Output
Value at ptr = 0x7ffe454c08cc
Value at var = 20
Value at *ptr = 20
Call-By-Value
#include <bits/stdc++.h>
using namespace std;
// Pass-by-Value
int square1(int n)
{
// Address of n in square1() is not the same as n1 in
// main()
cout << "address of n1 in square1(): " << &n << "\n";
square2(&n2);
cout << "Square of n2: " << n2 << "\n";
cout << "Change reflected in n2: " << n2 << "\n";
Output
address of n1 in main(): 0x7fffa7e2de64
address of n1 in square1(): 0x7fffa7e2de4c
Square of n1: 64
No change in n1: 8
address of n2 in main(): 0x7fffa7e2de68
address of n2 in square2(): 0x7fffa7e2de68
Square of n2: 64
Change reflected in n2: 64
address of n3 in main(): 0x7fffa7e2de6c
address of n3 in square3(): 0x7fffa7e2de6c
Square of n3: 64
Change reflected in n3: 64
In C++, by default arguments are passed by value and the changes made in the called
function will not reflect in the passed variable. The changes are made into a clone made by
the called function. If wish to modify the original copy directly (especially in passing huge
object or array) and/or avoid the overhead of cloning, we use pass-by-reference. Pass-by-
Reference with Reference Arguments does not require any clumsy syntax for referencing and
dereferencing.
Func琀椀on pointers in C
Pointer to a Func琀椀on
Output
Elements of the array are: 5 10 20
If pointer ptr is sent to a function as an argument, the array val can be accessed in a similar
fashion. Pointer vs Array
incremented ( ++ )
decremented ( — )
// Driver program
int main() { geeks(); }
Output
Value at ptr = 0x7ffe5a2d8060
Value at *ptr = 10
Value at ptr = 0x7ffe5a2d8064
Value at *ptr = 100
Value at ptr = 0x7ffe5a2d8068
Value at *ptr = 200
This declares an array with the literal representation for “geek”, and then a pointer to its first
element is assigned to ptr. If we imagine that “geek” is stored at the memory locations that
start at address 1800, we can represent the previous declaration as:
As pointers and arrays behave in the same way in expressions, ptr can be used to access the
characters of a string literal. For example:
char ptr = 0;
char x = *(ptr+3);
char y = ptr[3];
Pointers to pointers
In C++, we can create a pointer to a pointer that in turn may point to data or another pointer.
The syntax simply requires the unary operator (*) for each level of indirection while
declaring the pointer.
char a;
char *b;
char ** c;
a = ’g’;
b = &a;
c = &b;
Here b points to a char that stores ‘g’ and c points to the pointer b.
Void Pointers
This is a special type of pointer available in C++ which represents the absence of type. Void
pointers are pointers that point to a value that has no type (and thus also an undetermined
length and undetermined dereferencing properties). This means that void pointers have great
flexibility as they can point to any data type. There is a payoff for this flexibility. These
pointers cannot be directly dereferenced. They have to be first transformed into some other
pointer type that points to a concrete data type before being dereferenced.
// Declare an integer
int i = 10;
Output
*data points to a char
The new value of c is: y
*data points to an int
The new value of i is: 11
Invalid pointers
A pointer should point to a valid address but not necessarily to valid elements (like for
arrays). These are called invalid pointers. Uninitialized pointers are also invalid pointers.
int *ptr1;
int arr[10];
int *ptr2 = arr+20;
Here, ptr1 is uninitialized so it becomes an invalid pointer and ptr2 is out of bounds of arr so
it also becomes an invalid pointer. (Note: invalid pointers do not necessarily raise compile
errors)
NULL Pointers
A null pointer is a pointer that point nowhere and not just an invalid address. Following are 2
methods to assign a pointer as NULL;
int *ptr1 = 0;
int *ptr2 = NULL;
Advantages of Pointers
Pointers reduce the code and improve performance. They are used to retrieve strings, trees,
arrays, structures, and func琀椀ons.
In addi琀椀on to this, pointers allow us to access a memory loca琀椀on in the computer’s memory.