Unit Four
Unit Four
F. Y. B. Tech.
Course Material (A Brief Reference Version for Students)
You can clearly see that above process results in duplication of 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 rest of the three classes from base class(Vehicle).
Syntax:
Here, subclass_name is the name of the sub class, access_mode is the mode in which you
want to inherit this sub class for example: public, private etc. and base_class_name is the
name of the base class from which you want to inherit the sub 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.
#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
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
Public mode: If we derive a sub class 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 derived class.
Protected mode: If we derive a sub class from a Protected base class. Then both
public member and protected members of the base class will become protected in
derived class.
Private mode: If we derive a sub class from a Private base class. Then both public
member and protected members of the base class will become Private in 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 below example. It is just question of access.
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
};
Syntax:
// base class
class Vehicle {
public:
Vehicle()
{
cout << "This is a Vehicle" << endl;
}
};
};
// main function
int main()
{
// creating object of sub class will
// invoke the constructor of base classes
Car obj;
return 0;
}
Output:
This is a vehicle
2. Multiple Inheritance:
Multiple Inheritance is a feature of C++ where a class can inherit from more than one
classes, i.e. one sub class is inherited from more than one base classes.
Syntax:
};
// main function
int main()
{
// creating object of sub class will
// invoke the constructor of base classes
Car obj;
return 0;
}
Output:
This is a Vehicle
This is a 4 wheeler Vehicle
3. Multilevel Inheritance:
In this type of inheritance, a derived class is created from another derived class.
// base class
class Vehicle
{
public:
Vehicle()
{
cout << "This is a Vehicle" << endl;
}
};
class fourWheeler: public Vehicle
{ public:
fourWheeler()
{
cout<<"Objects with 4 wheels are vehicles"<<endl;
}
};
// sub class derived from two base classes
class Car: public fourWheeler{
public:
car()
{
cout<<"Car has 4 Wheels"<<endl;
}
};
// main function
int main()
{
//creating object of sub class will
//invoke the constructor of base classes
Car obj;
return 0;
}
Output:
This is a Vehicle
Objects with 4 wheels are vehicles
Car has 4 Wheels
4. Hierarchical Inheritance:
In this type of inheritance, more than one sub class is inherited from a single base class. i.e.
more than one derived class is created from a single base class.
};
};
// main function
int main()
{
// creating object of sub class will
// invoke the constructor of base class
Car obj1;
Bus obj2;
return 0;
}
Output:
This is a Vehicle
This is a Vehicle
5. Hybrid (Virtual) Inheritance:
Hybrid Inheritance is implemented by combining more than one type of inheritance. For
example: Combining Hierarchical inheritance and Multiple Inheritance.
Below image shows the combination of hierarchical and multiple inheritances:
#include <iostream>
using namespace std;
// base class
class Vehicle
{
public:
Vehicle()
{
cout << "This is a Vehicle" << endl;
}
};
//base class
class Fare
{
public:
Fare()
{
cout<<"Fare of Vehicle\n";
}
};
};
};
// main function
int main()
{
// creating object of sub class will
// invoke the constructor of base class
Bus obj2;
return 0;
}
Output:
This is a Vehicle
Fare of Vehicle
Static Members in C++
Defining static members in C++
Static members in a class in C++ can be defined using the static keyword. There is only one
copy of the static class member in memory, regardless of the number of objects of the class.
So the static member is shared by all the class objects.
The static class member is initialized to zero when the first object of the class is created if it
is not initialized in any other way.
A program that demonstrates the definition of the static class members is given as follows −
Example
#include <iostream>
using namespace std;
class Point{
int x;
int y;
public:
static int count;
count++;
}
void display(){
cout<<"The point is ("<<x<<","<<y<<")\n";
}
};
int Point::count = 0;
int main(void){
Point p1(10,5);
Point p2(7,9);
Point p3(1,2);
p1.display();
p2.display();
p3.display();
#include <iostream>
#include<string.h>
void putdata() {
cout<<"Roll Number = "<< rollNo <<endl;
cout<<"Name = "<< name <<endl;
cout<<"Marks = "<< marks <<endl;
cout<<endl;
}
};
int Student::objectCount = 0;
int main(void) {
Student s1;
s1.getdata();
s1.putdata();
Student s2;
s2.getdata();
s2.putdata();
Student s3;
s3.getdata();
s3.putdata();
cout << "Total objects created = " << Student::objectCount
<< endl;
return 0;
}
Output
In the above program, the class student has three data members denoting the student roll
number, name and marks. The objectCount data member is a static data member that
contains the number of objects created of class Student. Student() is a constructor that
increments object Count each time a new class object is created.
There are 2 member functions in class. The function getdata() obtains the data from the
user and putdata() displays the data.
In the function main(), there are three objects of class Student i.e. s1, s2 and s3. For each of
these objects getdata() and putdata() are called. At the end, the value of objectCount is
displayed.
When are static C++ class members initialized?
Static C++ class members can be defined using the static keyword. The static member in a
class is shared by all the class objects as there is only one copy of the static class member in
the memory, regardless of the number of objects of the class.
The static class member is initialized to zero when the first object of the class is created if it
is not initialized in any other way.
A program that demonstrates static class members in C++ is given as follows.
Example
#include <iostream>
using namespace std;
class Example {
public :
static int a;
int func() {
cout << "The value of static member a: " << a;
}
};
int Example::a = 20;
int main() {
Example obj;
obj.func();
return 0;
}
Output
class Box {
public:
static int objectCount;
// Constructor definition
Box(double l = 2.0, double b = 2.0, double h = 2.0) {
cout <<"Constructor called." << endl;
length = l;
breadth = b;
height = h;
int main(void) {
// Print total number of objects before creating object.
cout << "Inital Stage Count: " << Box::getCount() << endl;
return 0;
}
When the above code is compiled and executed, it produces the following result −
Inital Stage Count: 0
Constructor called.
Constructor called.
Final Stage Count: 2
Inline function in C++
Inline function is one of the important features of C++. So, let’s first understand why inline
functions are used and what is the purpose of inline function?
When the program executes the function call instruction the CPU stores the memory
address of the instruction following the function call, copies the arguments of the function
on the stack and finally transfers control to the specified function. The CPU then executes
the function code, stores the function return value in a predefined memory location/register
and returns control to the calling function. This can become overhead if the execution time
of function is less than the switching time from the caller function to called function (callee).
For functions that are large and/or perform complex tasks, the overhead of the function call
is usually insignificant compared to the amount of time the function takes to run. However,
for small, commonly-used functions, the time needed to make the function call is often a lot
more than the time needed to actually execute the function’s code. This overhead occurs
for small functions because execution time of small function is less than the switching time.
C++ provides an inline functions to reduce the function call overhead. Inline function is a
function that is expanded in line when it is called. When the inline function is called whole
code of the inline function gets inserted or substituted at the point of inline function call.
This substitution is performed by the C++ compiler at compile time. Inline function may
increase efficiency if it is small.
Remember, inlining is only a request to the compiler, not a command. Compiler can ignore
the request for inlining. Compiler may not perform inlining in such circumstances like:
1. If a function contains a loop. (for, while, do-while)
2. If a function contains static variables.
3. If a function is recursive.
4. If a function return type is other than void, and the return statement doesn’t exist in
function body.
5. If a function contains switch or goto statement.
1. The added variables from the inline function consumes additional registers, After in-
lining function if variables number which are going to use register increases than
they may create overhead on register variable resource utilization. This means that
when inline function body is substituted at the point of function call, total number of
variables used by the function also gets inserted. So the number of register going to
be used for the variables will also get increased. So if after function in lining variable
numbers increase drastically then it would surely cause an overhead on register
utilization.
2. If you use too many inline functions then the size of the binary executable file will be
large, because of the duplication of same code.
3. Too much in lining can also reduce your instruction cache hit rate, thus reducing the
speed of instruction fetch from that of cache memory to that of primary memory.
4. Inline function may increase compile time overhead if someone changes the code
inside the inline function then all the calling location has to be recompiled because
compiler would require to replace all the code once again to reflect the changes,
otherwise it will continue with old functionality.
5. Inline functions may not be useful for many embedded systems. Because in
embedded systems code size is more important than speed.
6. Inline functions might cause thrashing because inlining might increase size of the
binary executable file. Thrashing in memory causes performance of computer to
degrade.
Output:
The above style is considered as a bad programming style. The best programming style is to
just write the prototype of function inside the class and specify it as an inline in the function
definition.
For example:
class S
{
public:
int square(int s); // declare the function
};
#include <iostream>
using namespace std;
class operation
{
int a,b,add,sub,mul;
float div;
public:
void get();
void sum();
void difference();
void product();
void division();
};
inline void operation :: get()
{
cout << "Enter first value:";
cin >> a;
cout << "Enter second value:";
cin >> b;
}
int main()
{
cout << "Program using inline function\n";
operation s;
s.get();
s.sum();
s.difference();
s.product();
s.division();
return 0;
}
Output:
Example 1:
#include <iostream>
using namespace std;
int main() {
int var = 10;
int *p;
p = &var; // p points to the address of var
cout << "The address stored in p: " << p << endl;
cout << "The value that points to: " << *p << endl;
class Simple
{
public:
int a=10;
};
int main()
{
Simple obj;
Simple* ptr; // Pointer of class type
ptr = &obj;
Here you can see that we have declared a pointer of class type which points to
class's object. We can access data members and member functions using pointer
name with arrow -> symbol.
Polymorphism in C++
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, a person at the same time can have different characteristics. Like
a man at the same time is a father, a husband, an employee. So the same people possess
different behavior in different situations. This is called polymorphism. Polymorphism is
considered as one of the important features of Object Oriented Programming.
a. Function Overloading:
When there are multiple functions with same name but different parameters then these
functions are said to be overloaded. Functions can be overloaded by change in number of
arguments or/and change in type of arguments.
int main() {
Geeks obj1;
Output:
value of x is 7
value of x is 9.132
value of x and y is 85, 64
In the above example, a single function named func acts differently in three different
situations which is the property of polymorphism.
b. Operator Overloading:
C++ also provides option to overload operators. For example, we can make the operator
(‘+’) for string class to concatenate two strings. We know that this is the addition operator
whose task is to add two operands. So a single operator ‘+’ when placed between integer
operands, adds them and when placed between string operands, concatenates them.
Example:
class Complex {
private:
int real, imag;
public:
Complex(int r = 0, int i =0) {real = r; imag = i;}
12 + i9
In the above example the operator ‘+’ is overloaded. The operator ‘+’ is an addition operator
and can add two numbers(integers or floating point) but here the operator is made to
perform addition of two imaginary or complex numbers.
2. Runtime polymorphism:
This type of polymorphism is achieved by Function Overriding.
a. Function overriding
On the other hand 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.
#include <bits/stdc++.h>
using namespace std;
class base
{
public:
virtual void print ()
{ cout<< "print base class" <<endl; }
void show ()
{ cout<< "show base class" <<endl; }
};
void show ()
{ cout<< "show derived class" <<endl; }
};
//main function
int main()
{
base *bptr;
derived d;
bptr = &d;
return 0;
}
Output:
A virtual function is a member function which is declared within a base class and is re-
defined (Overridden) by a derived class. When you refer to a derived class object using a
pointer or a reference to the base class, you can call a virtual function for that object and
execute the derived class’s version of the function.
Virtual functions ensure that the correct function is called for an object, regardless of
the type of reference (or pointer) used for function call.
They are mainly used to achieve Runtime polymorphism
Functions are declared with a virtual keyword in base class.
The resolving of function call is done at Run-time.
Consider the following simple program showing run-time behavior of virtual functions.
#include <iostream>
using namespace std;
class base {
public:
virtual void print()
{
cout << "print base class" << endl;
}
void show()
{
cout << "show base class" << endl;
}
};
void show()
{
cout << "show derived class" << endl;
}
};
int main()
{
base* bptr;
derived d;
bptr = &d;
Explanation:
Runtime polymorphism is achieved only through a pointer (or reference) of base class type.
Also, a base class pointer can point to the objects of base class as well as to the objects of
derived class. In above code, base class pointer ‘bptr’ contains the address of object ‘d’ of
derived class.
Late binding (Runtime) is done in accordance with the content of pointer (i.e. location
pointed to by pointer) and Early binding(Compile time) is done according to the type of
pointer, since print() function is declared with virtual keyword so it will be bound at run-
time (output is print derived class as pointer is pointing to object of derived class ) and
show() is non-virtual so it will be bound during compile time(output is show base class as
pointer is of base type ).
NOTE: If we have created a virtual function in the base class and it is being overridden in the
derived class then we don’t need virtual keyword in the derived class, functions are
automatically considered as virtual functions in the derived class.
1. If object of that class is created then a virtual pointer (VPTR) is inserted as a data
member of the class to point to VTABLE of that class. For each new object created, a
new virtual pointer is inserted as a data member of that class.
2. Irrespective of object is created or not, a static array of function pointer called
VTABLE where each cell contains the address of each virtual function contained in
that class.
class base {
public:
void fun_1() { cout << "base-1\n"; }
virtual void fun_2() { cout << "base-2\n"; }
virtual void fun_3() { cout << "base-3\n"; }
virtual void fun_4() { cout << "base-4\n"; }
};
class derived : public base {
public:
void fun_1() { cout << "derived-1\n"; }
void fun_2() { cout << "derived-2\n"; }
void fun_4(int x) { cout << "derived-4\n"; }
};
int main()
{
base* p;
derived obj1;
p = &obj1;
base-1
derived-2
base-3
base-4
Explanation:
Initially, we create a pointer of type base class and initialize it with the address of the
derived class object. When we create an object of the derived class, the compiler creates a
pointer as a data member of the class containing the address of VTABLE of the derived class.
Similar concept of Late and Early Binding is used as in above example. For fun_1() function
call, base class version of function is called, fun_2() is overridden in derived class so derived
class version is called, fun_3() is not overridden in derived class and is virtual function so
base class version is called, similarly fun_4() is not overridden so base class version is called.
NOTE: fun_4(int) in derived class is different from virtual function fun_4() in base class as
prototype of both the function is different.
C++ Friend Functions
A friend function of a class is defined outside that class' scope but it has the right to access
all private and protected members of the class. Even though the prototypes for friend
functions appear in the class definition, friends are not member functions.
To declare a function as a friend of a class, precede the function prototype in the class
definition with keyword friend as follows −
class Box
{
double width;
public:
double length;
friend void printWidth( Box box );
void setWidth( double wid );
};
To declare all member functions of class ClassTwo as friends of class ClassOne, place a
following declaration in the definition of class ClassOne −
#include <iostream>
class Box {
double width;
public:
friend void printWidth( Box box );
void setWidth( double wid );
};
return 0;
}
When the above code is compiled and executed, it produces the following result −
Width of box: 10