OOP Concepts and Interview Questions
OOP Concepts and Interview Questions
Advantages of OOP
Something has gone wrong, and you have no idea where to look. When working with
object-oriented programming languages, you know exactly where to look. “Oh, the car
object broke down? The problem must be in the Car class!” You don’t have to muck
through anything else.
That’s the beauty of encapsulation. Objects are self-contained, and each bit of
functionality does its own thing while leaving the other bits alone. Also, this modality
allows an IT team to work on multiple objects simultaneously while minimizing the
chance that one person might duplicate someone else’s functionality.
Suppose that in addition to your Car object, one colleague needs a RaceCar object, and
another needs a Limousine object. Everyone builds their objects separately but discover
commonalities between them. In fact, each object is really just a different kind of Car.
This is where the inheritance technique saves time: Create one generic class (Car), and
then define the subclasses (RaceCar and Limousine) that are to inherit the generic
class’s traits.
Of course, Limousine and RaceCar still have their unique attributes and functions. If the
RaceCar object needs a method to “fireAfterBurners” and the Limousine object requires
a Chauffeur, each class could implement separate functions just for itself. However,
because both classes inherit key aspects from the Car class, for example the “drive” or
M Muzammal Murtaza - BITF16A525
“fillUpGas” methods, your inheriting classes can simply reuse existing code instead of
writing these functions all over again.
What if you want to make a change to all Car objects, regardless of type? This is
another advantage of the OO approach. Simply make a change to your Car class, and
all car objects will simply inherit the new code.
Riffing on this example, you now need just a few drivers, or functions, like “driveCar,”
driveRaceCar” and “DriveLimousine.” RaceCarDrivers share some traits with
LimousineDrivers, but other things, like RaceHelmets and BeverageSponsorships, are
unique.
A language like C has an amazing legacy in programming history, but writing software
in a top-down language is like playing Jenga while wearing mittens. The more complex
it gets, the greater the chance it will collapse. Meanwhile, writing a functional-style
program in a language like Haskell or ML can be a chore.
Object-oriented programming is often the most natural and pragmatic approach, once
you get the hang of it. OOP languages allow you to break down your software into
bite-sized problems that you then can solve — one object at a time.
M Muzammal Murtaza - BITF16A525
This isn’t to say that OOP is the One True Way. However, the advantages of
object-oriented programming are many. When you need to solve complex programming
challenges and want to add code tools to your skill set, OOP is your friend — and has
much greater longevity and utility than Pac-Man or parachute pants.
___________________________________________________________________
Struct vs class
1. Class can create a subclass that will inherit parent's properties and methods,
whereas Structure does not support the inheritance.
2. A class has all members private by default. A struct is a class where members
are public by default.
3. Classes allow you to perform cleanup (garbage collector) before the object is
deallocated because the garbage collector works on heap memory. Objects are
usually deallocated when instance is no longer referenced by other code.
Structures can not be garbage collector so no efficient memory management.
4. Size of the empty class is 1 Byte whereas Sizeof empty structure is 0 Bytes.
___________________________________________________________________
If you make any variable constant, using const keyword, you cannot change its value.
Also, the constant variables must be initialized while they are declared.
const data members of a class may be declared as const . Such a data member must
be initialized by the constructor using an initialization list. Once initialized, a const data
member may never be modified, not even in the constructor or destructor.
The const property of an object goes into effect after the constructor finishes executing
and ends before the class's destructor executes. So the constructor and destructor can
modify the object, but other methods of the class can't.
Only const methods can be called for a const object. Objects that are not const can call
either const or non-const methods.
M Muzammal Murtaza - BITF16A525
Constructors and destructors can never be declared as const. They are always allowed
to modify an object even if the object is const.
___________________________________________________________________
Static Variables in a class: A s the variables declared as static are initialized only once
as they are allocated space in separate static storage, so the static variables in a class
are shared by the objects. There can not be multiple copies of the same static variables
for different objects. Also because of this reason static variables can not be initialized
using constructors.
Static functions in a class: Just like the static data members or static variables inside
the class, static member functions also do not depend on the object of the class. We are
allowed to invoke a static member function using the object and the ‘.’ operator but it is
recommended to invoke the static members using the class name and the scope
resolution operator.
Class objects as static: Just like variables, objects also when declared as static have
a scope till the lifetime of the program.
___________________________________________________________________
Access specifiers
Types of modifiers
● Public
● Private
● Protected
● Internal
● Protected Internal
M Muzammal Murtaza - BITF16A525
Public
Private
Protected
Internal
Accessible anywhere in the code within the assembly. But not accessible in
another assembly.
Protected Internal
Accessible anywhere in the code within the assembly. And accessible only in
derived class in another assembly.
___________________________________________________________________
Encapsulation in C++
In normal terms Encapsulation i s defined as wrapping up of data and information under
Consider a real life example of encapsulation, in a company there are different sections
like the accounts section, finance section, sales section etc. The finance section
handles all the financial transactions and keeps records of all the data related to
finance. Similarly the sales section handles all the sales related activities and keeps
records of all the sales. Now there may arise a situation when for some reason an
official from the finance section needs all the data about sales in a particular month. In
this case, he is not allowed to directly access the data of the sales section. He will first
M Muzammal Murtaza - BITF16A525
have to contact some other officer in the sales section and then request him to give the
particular data. This is what encapsulation is. Here the data of the sales section and the
employees that can manipulate them are wrapped under a single name “sales section”.
hides the data. In the above example the data of any of the sections like sales, finance
In C++ encapsulation can be implemented using Class and access modifiers. Look at
#include<iostream>
using namespace std;
class Encapsulation
{
private:
// data hidden from outside world
int x;
public:
// function to set value of
// variable x
void set(int a)
{
x =a;
}
// main function
int main()
{
Encapsulation obj;
obj.set(5);
cout<<obj.get();
return 0;
}
M Muzammal Murtaza - BITF16A525
output:
In the above program the variable x is made private. This variable can be accessed and
manipulated only using the functions get() and set() which are present inside the class.
Thus we can say that here, the variable x and the functions get() and set() are binded
1. The data members should be labeled as private using the private access
specifiers
2. The member function which manipulates the data members should be
labeled as public using the public a
ccess specifier
___________________________________________________________________
Abstraction in C++
Data abstraction is one of the most essential and important features of object oriented
hiding the details. Data abstraction refers to providing only essential information about
the data to the outside world, hiding the background details or implementation.
Consider a real life example of a man driving a car. The man only knows that pressing
the accelerators will increase the speed of the car or applying brakes will stop the car
M Muzammal Murtaza - BITF16A525
but he does not know about how on pressing accelerator the speed is actually
increasing, he does not know about the inner mechanism of the car or the
implementation of accelerator, brakes etc in the car. This is what abstraction is.
Abstraction using Classes: We can implement Abstraction in C++ using classes. Class
helps us to group data members and member functions using available access
specifiers. A Class can decide which data members will be visible to the outside world
For example, consider the pow() method present in the math.h header file. Whenever we
need to calculate power of a number, we simply call the function pow() present in the
math.h header file and pass the numbers as arguments without knowing the underlying
We can easily implement abstraction using the above two features provided by access
specifiers. Say, the members that define the internal implementation can be marked as
M Muzammal Murtaza - BITF16A525
private in a class. And the important information needed to be given to the outside
world can be marked as public. And these public members can access the private
Example:
#include <iostream>
using namespace std;
class implementAbstraction
{
private:
int a, b;
public:
void display()
{
cout<<"a = " <<a << endl;
cout<<"b = " << b << endl;
}
};
int main()
{
implementAbstraction obj;
obj.set(10, 20);
obj.display();
return 0;
}
M Muzammal Murtaza - BITF16A525
Output:
a = 10
b = 20
You can see in the above program we are not allowed to access the variables a and b
directly, however one can call the function set() to set the values in a and b and the
___________________________________________________________________
Encapsulation VS Abstraction
The most important difference between Abstraction and Encapsulation is that
Abstraction solves the problem at design level while Encapsulation solves it
implementation level.
Abstraction is about hiding unwanted details while giving out most essential details,
while Encapsulation means hiding the code and data into a single unit e.g. class or
method to protect inner workings of an object from the outside world.
M Muzammal Murtaza - BITF16A525
___________________________________________________________________
C++ constructor call order will be from top to down that is from base class to derived
class and c++ destructor call order will be in reverse order.
___________________________________________________________________
Virtual destructor
Deleting a derived class object using a pointer to a base class that has a non-virtual
destructor results in undefined behavior. To correct this situation, the base class should
undefined behavior.
M Muzammal Murtaza - BITF16A525
class base {
public:
base()
{ cout<<"Constructing base \n"; }
~base()
{ cout<<"Destructing base \n"; }
};
int main(void)
{
derived *d = new derived();
base *b = d;
delete b;
getchar();
return 0;
}
Although the output of following program may be different on different compilers, when
Constructing base
Constructing derived
Destructing base
M Muzammal Murtaza - BITF16A525
Making base class destructor virtual guarantees that the object of derived class is
destructed properly, i.e., both base class and derived class destructors are called. For
example,
class base {
public:
base()
{ cout<<"Constructing base \n"; }
virtual ~base()
{ cout<<"Destructing base \n"; }
};
int main(void)
{
derived *d = new derived();
base *b = d;
delete b;
getchar();
return 0;
}
Output:
Constructing base
Constructing derived
Destructing derived
M Muzammal Murtaza - BITF16A525
Destructing base
___________________________________________________________________
1)When instantiating one object and initializing it with values from another object.
2)When passing an object by value.
3)When an object is returned from a function by value.
This initializes the new object with an This assigns the value of one object to
already existing object another object both of which already exists.
Copy constructor is used when a new This operator is used when we want to
object is created with some existing assign an existing object to a new object.
object
Both the objects uses separate One memory location is used but different
memory locations. reference variables are pointing to the same
location.
___________________________________________________________________
Inheritance
Inheritance is one of the key features of Object-oriented programming in C++. It allows
the user to create a new class (derived class) from an existing class(base class). The
M Muzammal Murtaza - BITF16A525
derived class inherits all the features from the base class and can have additional
features of its own.
Since, all of the characters are persons, they can walk and talk. However,
they also have some special skills. A maths teacher can teach maths, a
footballer can play football and a businessman can run a business.
You can individually create three classes who can walk, talk and perform their
special skill as shown in the figure below.
In each of the classes, you would be copying the same code for walk and talk
for each character.
If you want to add a new feature - eat, you need to implement the same code
for each character. This can easily become error prone (when copying) and
duplicate codes.
M Muzammal Murtaza - BITF16A525
It'd be a lot easier if we had a Person class with basic features like talk, walk,
eat, sleep, and add special skills to those features as per our characters. This
is done using inheritance.
Using inheritance, now you don't implement the same code for walk and talk
for each class. You just need to inherit them.
So, for Maths teacher (derived class), you inherit all features of a Person
(base class) and add a new feature TeachMaths. Likewise, for a footballer,
you inherit all the features of a Person and add a new feature PlayFootball
and so on.
class Person
{
... .. ...
};
In the above example, class Person is a base class and classes MathsTeacher
and Footballer are the derived from Person.
The derived class appears with the declaration of a class followed by a colon,
the keyword public and the name of base class from which it is derived.
Since, MathsTeacher and Footballer are derived from Person, all data member
and member function of Person can be accessible from them.
class P erson
{
public:
string profession;
int age;
int main()
{
MathsTeacher teacher;
teacher.profession = "Teacher";
teacher.age = 23;
teacher.display();
teacher.teachMaths();
Footballer footballer;
footballer.profession = "Footballer";
footballer.age = 19;
footballer.display();
M Muzammal Murtaza - BITF16A525
footballer.playFootball();
return 0;
}
output
My profession is: Teacher
My age is: 23
I can walk.
I can talk.
I can teach Maths.
My profession is: Footballer
My age is: 19
I can walk.
I can talk.
I can play Football.
In this program, Person is a base class, while MathsTeacher and Footballer are
derived from Person.
Person class has two data members - profession and age. It also has two
member functions - walk() and talk().
Both MathsTeacher and Footballer can access all data members and member
functions of Person.
Since, it has access to Person's data members, profession and age of teacher
is set. This data is displayed using the display() function defined in the Person
M Muzammal Murtaza - BITF16A525
When creating a derived class from a base class, you can use different
access specifiers to inherit the data members of the base class.
In the above example, the base class Person has been inherited public-ly by
MathsTeacher and Footballer.
You can declare a derived class from a base class with different access
control, i.e., public inheritance, protected inheritance or private inheritance.
#include <iostream>
class base
};
};
class base
public:
int x;
protected:
int y;
M Muzammal Murtaza - BITF16A525
private:
int z;
};
// x is public
// y is protected
};
// x is protected
// y is protected
};
// x is private
// y is private
● base has three member variables: x, y and z which are public,
protected and private member respectively.
● publicDerived inherits variables x and y as public and protected. z is not
inherited as it is a private member variable of base.
● protectedDerived inherits variables x and y. Both variables become
protected. z is not inherited
If we derive a class derivedFromProtectedDerived from protectedDerived,
variables x and y are also inherited to the derived class.
● privateDerived inherits variables x and y. Both variables become
private. z is not inherited
If we derive a class derivedFromPrivateDerived from privateDerived,
variables x and y are not inherited because they are private variables of
privateDerived.
M Muzammal Murtaza - BITF16A525
(inherited as protected
variables)
own
class?
Accessi no no no
ble from
2nd
derived
class?
class.
The constructors of inherited classes are called in the same order in which they are
inherited. For example, in the following program, B’s constructor is called before A’s
constructor.
M Muzammal Murtaza - BITF16A525
#include<iostream>
using namespace std;
class A
{
public:
A() { cout << "A's constructor called" << endl; }
};
class B
{
public:
B() { cout << "B's constructor called" << endl; }
};
int main()
{
C c;
return 0;
}
Output:
The diamond problem occurs when two superclasses of a class have a common base
class. For example, in the following diagram, the TA class gets two copies of all
#include<iostream>
using namespace std;
class Person {
// Data members of person
public:
Person(int x) { cout << "Person::Person(int ) called" <<
endl; }
};
}
};
int main() {
TA ta1(30);
}
Person::Person(int ) called
Faculty::Faculty(int ) called
Person::Person(int ) called
Student::Student(int ) called
TA::TA(int ) called
In the above program, constructor of ‘Person’ is called two times. Destructor of ‘Person’
will also be called two times when object ‘ta1’ is destructed. So object ‘ta1’ has two
copies of all members of ‘Person’, this causes ambiguities. The solution to this problem
is ‘virtual’ keyword. We make the classes ‘Faculty’ and ‘Student’ as virtual base classes
to avoid two copies of ‘Person’ in ‘TA’ class. For example, consider the following
program.
M Muzammal Murtaza - BITF16A525
#include<iostream>
using namespace std;
class Person {
public:
Person(int x) { cout << "Person::Person(int ) called" <<
endl; }
Person() { cout << "Person::Person() called" << endl; }
};
int main() {
TA ta1(30);
}
Output:
Person::Person() called
Faculty::Faculty(int ) called
Student::Student(int ) called
M Muzammal Murtaza - BITF16A525
TA::TA(int ) called
___________________________________________________________________
A shallow copy of an object copies all of the member field values. This works well if the fields
are values, but may not be what you want for fields that point to dynamically allocated memory.
The pointer will be copied. but the memory it points to will not be copied -- the field in both the
original object and the copy will then point to the same dynamically allocated memory, which is
not usually what you want. The default copy constructor and assignment operator make shallow
copies.
A deep copy copies all fields, and makes copies of dynamically allocated memory pointed to by
the fields. To make a deep copy, you must write a copy constructor and overload the
assignment operator, otherwise the copy will point to the original, with disastrous
consequences.
If an object has pointers to dynamically allocated memory, and the dynamically allocated
memory needs to be copied when the original object is copied, then a deep copy is required.
A class that requires deep copies generally needs:
● A constructor to either make an initial allocation or set the pointer to NULL.
● A destructor to delete the dynamically allocated memory.
● A copy constructor to make a copy of the dynamically allocated memory.
● An overloaded assignment operator to make a copy of the dynamically allocated
memory.
___________________________________________________________________
But, sometimes this restriction may force programmers to write long and complex codes. So,
there is a mechanism built in C++ programming to access private or protected data from
non-member functions.
M Muzammal Murtaza - BITF16A525
The compiler knows a given function is a friend function by the use of the keyword friend.
For accessing the data, the declaration of a friend function should be made inside the body of
the class (can be anywhere inside class either in private or public section) starting with keyword
friend.
class className
{
... .. ...
friend return_type functionName(argument/s);
... .. ...
}
return_type functionName(argument/s)
{
... .. ...
// Private and protected data of className can be accessed from
// this function because it is a friend function of className.
... .. ...
}
class Distance
{
private:
int meter;
public:
Distance(): meter(0) { }
//friend function
friend int addFive(Distance);
};
int main()
{
Distance D;
cout<<"Distance: "<< addFive(D);
return 0;
}
Output
Distance: 5
Here, friend function addFive() is declared inside Distance class. So, the private data meter can
be accessed from this function.
Though this example gives you an idea about the concept of a friend function, it doesn't show
any meaningful use.
A more meaningful use would to when you need to operate on objects of two different classes.
That's when the friend function can be very helpful.
You can definitely operate on two objects of different classes without using the friend function
but the program will be long, complex and hard to understand.
M Muzammal Murtaza - BITF16A525
// forward declaration
class B;
class A {
private:
int numA;
public:
A(): numA(12) { }
// friend function declaration
friend int add(A, B);
};
class B {
private:
int numB;
public:
B(): numB(1) { }
// friend function declaration
friend int add(A , B);
};
int main()
{
A objectA;
B objectB;
cout<<"Sum: "<< add(objectA, objectB);
return 0;
}
Output
Sum: 13
M Muzammal Murtaza - BITF16A525
In this program, classes A and B have declared add() as a friend function. Thus, this function
can access private data of both class.
Here, add() function adds the private data numA and numB of two objects objectA and objectB,
and returns it to the main function.
To make this program work properly, a forward declaration of a class class B should be made
as shown in the above example.
This is because class B is referenced within the class A using code: friend int add(A , B);.
... .. ...
class B;
class A
{
// class B is a friend class of class A
friend class B;
... .. ...
}
class B
{
... .. ...
}
When a class is made a friend class, all the member functions of that class becomes friend
functions.
In this program, all member functions of class B will be friend functions of class A. Thus, any
member function of class B can access the private and protected data of class A. But, member
functions of class A cannot access the data of class B.
___________________________________________________________________
M Muzammal Murtaza - BITF16A525
Operator overloading
You can redefine or overload most of the built-in operators available in C++. Thus, a
programmer can use operators with user-defined types as well.
Overloaded operators are functions with special names: the keyword "operator" followed by the
symbol for the operator being defined. Like any other function, an overloaded operator has a
return type and a parameter list.
Box operator+(const Box&);
declares the addition operator that can be used to add two Box objects and returns final Box
object. Most overloaded operators may be defined as ordinary non-member functions or as
class member functions. In case we define above function as non-member function of a class
then we would have to pass two arguments for each operand as follows −
Box operator+(const Box&, const Box&);
Following is the example to show the concept of operator over loading using a member function.
Here an object is passed as an argument whose properties will be accessed using this object,
the object which will call this operator can be accessed using this operator as explained below
#include <iostream>
using namespace std;
class Box {
public:
double getVolume(void) {
return length * breadth * height;
}
void setLength( double len ) {
length = len;
}
void setBreadth( double bre ) {
breadth = bre;
}
void setHeight( double hei ) {
height = hei;
}
private:
double length; // Length of a box
double breadth; // Breadth of a box
double height; // Height of a box
};
// box 1 specification
Box1.setLength(6.0);
Box1.setBreadth(7.0);
Box1.setHeight(5.0);
// box 2 specification
Box2.setLength(12.0);
Box2.setBreadth(13.0);
Box2.setHeight(10.0);
// volume of box 1
volume = Box1.getVolume();
cout << "Volume of Box1 : " << volume <<endl;
// volume of box 2
volume = Box2.getVolume();
cout << "Volume of Box2 : " << volume <<endl;
// volume of box 3
volume = Box3.getVolume();
cout << "Volume of Box3 : " << volume <<endl;
M Muzammal Murtaza - BITF16A525
return 0;
}
When the above code is compiled and executed, it produces the following result −
Volume of Box1 : 210
Volume of Box2 : 1560
Volume of Box3 : 5400
:: .* . ?:
___________________________________________________________________
We must know the following things before we start overloading these operators.
them to access private data members of class, we must make them friends.
member of the object on the left side of the operator. For example, consider the
statement “ob1 + ob2” (let ob1 and ob2 be objects of two different classes). To make
this statement compile, we must overload ‘+’ in class of ‘ob1’ or make ‘+’ a global
function.
M Muzammal Murtaza - BITF16A525
The operators ‘<<' and '>>' are called like 'cout << ob1' and 'cin >> ob1'. So if we want to
make them a member method, then they must be made members of ostream and
istream classes, which is not a good option most of the time. Therefore, these
operators are overloaded as global functions with two parameters, cout and object of
#include <iostream>
using namespace std;
class Complex
{
private:
int real, imag;
public:
Complex(int r = 0, int i =0)
{ real = r; imag = i; }
friend ostream & operator << (ostream &out, const Complex
&c);
friend istream & operator >> (istream &in, Complex &c);
};
int main()
{
Complex c1;
cin >> c1;
cout << "The complex object is ";
cout << c1;
return 0;
}
M Muzammal Murtaza - BITF16A525
Output:
___________________________________________________________________
Function Overloading
You can have multiple definitions for the same function name in the same
scope. The definition of the function must differ from each other by the
types and/or the number of arguments in the argument list. You cannot
overload function declarations that differ only by return type.
Following is the example where same function print() is being used to print
different data types −
Live Demo
#include <iostream>
using namespace std;
class printData {
public:
void print(int i) {
cout << "Printing int: " << i << endl;
}
void print(double f) {
cout << "Printing float: " << f << endl;
}
void print(char* c) {
cout << "Printing character: " << c << endl;
}
};
int main(void) {
printData pd;
pd.print(500.263);
return 0;
}
When the above code is compiled and executed, it produces the following
result −
Printing int: 5
Printing float: 500.263
Printing character: Hello C++
___________________________________________________________________
Function overloading
Function overloading is a C++ programming feature that allows us to have more
than one function having same name but different parameter list, when I say
parameter list, it means the data type and sequence of the parameters, for
example the parameters list of a function myfuncn(int a, float b) is (int, float)
which is different from the function myfuncn(float a, int b) parameter list (float,
int). Function overloading is a compile-time polymorphism.
Now that we know what is parameter list lets see the rules of overloading: we can
have following functions in the same scope.
The easiest way to remember this rule is that the parameters should qualify any
one or more of the following conditions, they should have different type, number
or sequence of parameters.
For example:
M Muzammal Murtaza - BITF16A525
#include <iostream>
using namespace std;
class Addition {
public:
int sum(int num1,int num2) {
return num1+num2;
}
int sum(int num1,int num2, int num3) {
return num1+num2+num3;
}
};
int main(void) {
Addition obj;
cout<<obj.sum(20, 15)<<endl;
cout<<obj.sum(81, 100, 10);
return 0;
M Muzammal Murtaza - BITF16A525
}
Output:
35
191
Function overloading Example 2
As I mentioned in the beginning of this guide that functions having different return
types and same parameter list cannot be overloaded. However if the functions
have different parameter lists then they can have same or different return types
to be eligible for overloading. In short the return type of a function does not play
any role in function overloading. All that matters is the parameter list of function.
#include <iostream>
using namespace std;
class DemoClass {
public:
int demoFunction(int i) {
return i;
}
double demoFunction(double d) {
return d;
}
};
int main(void) {
DemoClass obj;
cout<<obj.demoFunction(100)<<endl;
cout<<obj.demoFunction(5005.516);
return 0;
}
Output:
100
5006.52
Advantages of Function overloading
integer numbers, if we wanted we could have some more functions with same
name and four or five arguments.
___________________________________________________________________
Function overriding
Function overriding is a feature that allows us to have the same function in child
class which is already present in the parent class. A child class inherits the data
members and member functions of parent class, but when you want to override a
functionality in the child class then you can use function overriding. It is like
creating a new version of an old function, in the child class.
Function Overriding Example
To override a function you must have the same signature in child class. By
signature I mean the data type and sequence of parameters. Here we don’t have
any parameter in the parent function so we didn’t use any parameter in the child
function.
#include <iostream>
using namespace std;
class BaseClass {
public:
void disp(){
cout<<"Function of Parent Class";
}
};
class DerivedClass: public BaseClass{
public:
void disp() {
M Muzammal Murtaza - BITF16A525
Note: In function overriding, the function in parent class is called the overridden
function and function in child class is called overriding function.
As we have seen above that when we make the call to function (involved in
overriding), the child class function (overriding function) gets called. What if you
want to call the overridden function by using the object of child class. You can do
that by creating the child class object in such a way that the reference of parent
class points to it. Lets take an example to understand it.
#include <iostream>
using namespace std;
class BaseClass {
public:
void disp(){
cout<<"Function of Parent Class";
}
};
class DerivedClass: public BaseClass{
public:
void disp() {
M Muzammal Murtaza - BITF16A525
parent_class_name::function_name
To do this in the above example, we can write following statement in the disp()
function of child class:
BaseClass::disp();
___________________________________________________________________
___________________________________________________________________
Polymorphism
The word polymorphism means having many forms. Typically, polymorphism occurs
when there is a hierarchy of classes and they are related by inheritance.
C++ polymorphism means that a call to a member function will cause a different
function to be executed depending on the type of object that invokes the function.
Consider the following example where a base class has been derived by other two
classes −
#include <iostream>
using namespace std;
class Shape {
protected:
int width, height;
public:
Shape( int a = 0, int b = 0){
width = a;
height = b;
}
M Muzammal Murtaza - BITF16A525
int area() {
cout << "Parent class area :" <<endl;
return 0;
}
};
class Rectangle: p ublic Shape {
public:
Rectangle( i nt a = 0, int b = 0):Shape(a, b) { }
shape->area();
return 0;
}
When the above code is compiled and executed, it produces the following result −
Parent class area :
Parent class area :
The reason for the incorrect output is that the call of the function area() is being set
once by the compiler as the version defined in the base class. This is called static
resolution of the function call, or static linkage - the function call is fixed before the
program is executed. This is also sometimes called early binding because the area()
function is set during the compilation of the program.
But now, let's make a slight modification in our program and precede the declaration of
area() in the Shape class with the keyword virtual so that it looks like this −
class Shape {
protected:
int width, height;
public:
Shape( int a = 0, int b = 0) {
width = a;
height = b;
}
virtual int area() {
cout << "Parent class area :" <<endl;
return 0;
}
};
After this slight modification, when the previous example code is compiled and
executed, it produces the following result −
Rectangle class area
Triangle class area
M Muzammal Murtaza - BITF16A525
This time, the compiler looks at the contents of the pointer instead of it's type. Hence,
since addresses of objects of tri and rec classes are stored in *shape the respective
area() function is called.
As you can see, each of the child classes has a separate implementation for the
function area(). This is how polymorphism is generally used. You have different classes
with a function of the same name, and even the same parameters, but with different
implementations.
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.
● 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.
● A virtual function must be defined in the base class, even though it is not used.
● The prototypes of a virtual function of the base class and all the derived classes must
be identical. If the two functions with the same name but different prototypes, C++
will consider them as the overloaded functions.
1. #include <iostream>
2. using namespace std;
3. class A
4. {
5. int x=5;
6. public:
7. void display()
8. {
9. std::cout << "Value of x is : " << x<<std::endl;
10. }
11. };
12. class B: public A
13. {
14. int y = 10;
15. public:
16. void display()
17. {
18. std::cout << "Value of y is : " <<y<< std::endl;
19. }
20. };
21. int main()
22. {
23. A *a;
24. B b;
25. a = &b;
26. a->display();
M Muzammal Murtaza - BITF16A525
27. return 0;
28. }
Output:
Value of x is : 5
In the above example, * a is the base class pointer. The pointer can only access the base
class members but not the members of the derived class. Although C++ permits the base
pointer to point to any object derived from the base class, it cannot directly access the
members of the derived class. Therefore, there is a need for virtual function which allows
the base pointer to access the members of the derived class.
1. #include <iostream>
2. {
3. public:
4. virtual void display()
5. {
6. cout << "Base class is invoked"<<endl;
7. }
8. };
9. class B:public A
10. {
11. public:
12. void display()
13. {
14. cout << "Derived Class is invoked"<<endl;
15. }
16. };
17. int main()
18. {
19. A* a; //pointer of base class
20. B b; //object of derived class
M Muzammal Murtaza - BITF16A525
21. a = &b;
22. a->display(); //Late Binding occurs
23. }
Output:
___________________________________________________________________
● A virtual function is not used for performing any task. It only serves as a
placeholder.
● 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.
1. #include <iostream>
2. using namespace std;
3. class Base
4. {
M Muzammal Murtaza - BITF16A525
5. public:
6. virtual void show() = 0;
7. };
8. class Derived : public Base
9. {
10. public:
11. void show()
12. {
13. std::cout << "Derived class is derived from the base class." << std::endl;
14. }
15. };
16. int main()
17. {
18. Base *bptr;
19. //Base b;
20. Derived d;
21. bptr = &d;
22. bptr->show();
23. return 0;
24. }
Output:
In the above example, the base class contains the pure virtual function. Therefore, the base
class is an abstract base class. We cannot create the object of the base class.
M Muzammal Murtaza - BITF16A525
https://www.techiedelight.com/difference-between-static-dynamic-binding-cpp/#:~:text=In%20st
atic%20binding%2C%20the%20function,available%20at%20the%20compile%2Dtime.
___________________________________________________________________
M Muzammal Murtaza - BITF16A525
Virtual table
https://pabloariasal.github.io/2017/06/10/understanding-virtual-tables/
___________________________________________________________________
Templates
Templates are powerful features of C++ which allows you to write generic
programs. In simple terms, you can create a single function or a class to work
with different data types using templates.
Templates are often used in larger codebase for the purpose of code
reusability and flexibility of the programs.
● Function Templates
● Class Templates
Function Templates
A single function template can work with different data types at once but, a
single normal function can only work with one set of data types.
M Muzammal Murtaza - BITF16A525
In the above code, T is a template argument that accepts different data types
(int, float), and class is a keyword.
You can also use keyword typename instead of class in the above example.
#include <iostream>
using namespace std;
// template function
template <class T>
T Large(T n1, T n2)
{
return (n1 > n2) ? n1 : n2;
}
int main()
{
int i1, i2;
float f1, f2;
char c1, c2;
return 0;
}
Output
12.4 is larger.
In the above program, a function template Large() is defined that accepts two
arguments n1 and n2 of data type T. T signifies that argument can be of any
data type.
Large() function returns the largest among the two arguments using a simple
conditional operation.
Inside the main() function, variables of three different data types: int, float
and char are declared. The variables are then passed to the Large() function
template as normal functions.
Similarly, when floating-point data and char data are passed, it knows the
argument data types and generates the Large() function accordingly.
This way, using only a single function template replaced three identical normal
functions and made your code maintainable.
#include <iostream>
using namespace std;
int main()
{
int i1 = 1, i2 = 2;
float f1 = 1.1, f2 = 2.2;
char c1 = 'a', c2 = 'b';
Swap(i1, i2);
Swap(f1, f2);
Swap(c1, c2);
return 0;
}
Output
f1 = 1.1
f2 = 2.2
c1 = a
c2 = b
The Swap() function template takes two arguments and swaps them by
reference.
Class Templates
Like function templates, you can also create class templates for generic class
operations.
Sometimes, you need a class implementation that is same for all classes, only
the data types used are different.
Normally, you would need to create a different class for each data type OR
create different member variables and functions within a single class.
M Muzammal Murtaza - BITF16A525
This will unnecessarily bloat your code base and will be hard to maintain, as a
change is one class/function should be performed on all classes/functions.
However, class templates make it easy to reuse the same code for all data
types.
In the above declaration, T is the template argument which is a placeholder for
the data type used.
Inside the class body, a member variable var and a member function
someOperation() are both of type T.
To create a class template object, you need to define the data type inside a <
> when creation.
className<dataType> classObject;
M Muzammal Murtaza - BITF16A525
For example:
className<int> classObject;
className<float> classObject;
className<string> classObject;
Program to add, subtract, multiply and divide two numbers using class
template
#include <iostream>
using namespace std;
public:
Calculator(T n1, T n2)
{
num1 = n1;
num2 = n2;
}
void displayResult()
{
cout << "Numbers are: " << num1 << " and " << num2 << "." <<
endl;
cout << "Addition is: " << add() << endl;
cout << "Subtraction is: " << subtract() << endl;
cout << "Product is: " << multiply() << endl;
cout << "Division is: " << divide() << endl;
}
int main()
{
Calculator<int> intCalc(2, 1);
Calculator<float> floatCalc(2.4, 1.2);
return 0;
}
Output
Int results:
Numbers are: 2 and 1.
Addition is: 3
Subtraction is: 1
Product is: 2
Division is: 2
Float results:
Numbers are: 2.4 and 1.2.
Addition is: 3.6
Subtraction is: 1.2
Product is: 2.88
Division is: 2
The class contains two private members of type T: num1 & num2, and a
constructor to initalize the members.
In the main() function, two different Calculator objects intCalc and floatCalc
are created for data types: int and float respectively. The values are
initialized using the constructor.
Notice we use <int> and <float> while creating the objects. These tell the
compiler the data type used for the class creation.
This creates a class definition each for int and float, which are then used
accordingly.
___________________________________________________________________