C++ Material
C++ Material
C++ Material
This book softcopy is available in pdfhost.io website, to download the file, search through keyword ‘cfamily’,
This pdf file(s) designed for 2-sided print-copy (Xerox copy).
I request you to rate the C-Family on Google review.
2 preface | C-Family
About C
C-language is an ideal programming language and a perfect combination of power and flexibility. Though it is
a high-level language, it has low level features as well as easy interaction with hardware and OS. Even
assembly language code can be mixed in it. It is accepted as a good system programming language. Powerful
OS like UNIX was developed using C.
‘C’ is widely used in the software industry for both system and application side development. C is the
primary subject in computer science. It lays good foundation in programming and eases the learning of
any advanced courses that are to follow. So, it has been added in every branch of arts, science, and
engineering as part of curriculum. Every graduate student is going to face C, C++, DS, Java, Python and
Oracle in the first & second academic years.
About C++
C++ is a successor to the C language. It introduces you to the exciting world of object-oriented
programming. Once you experience the magic of object-oriented programming, you'll never want to
leave it. Among all the available object-oriented programming languages, C++ stands out as the ideal
choice. With C++, you can create portable class components that can even be reused in other languages.
Thanks to these advantages, C++ is widely used in multi-tier enterprise applications.
I am grateful to all the students, friends, staff who helped me making this material. This book is advisable
to learn the logic and programming skills for beginners. For any suggestions contact me on
srihari.vijayawada@gmail.com
3 preface | C-Family
Introduction to C++
C is a structured and function-oriented language. Structured means the language provides good control
statements along with building blocks of code defined by braces { } . And also breaks down a big program
into several functions. Therefore, it is said to be a structured programming language as well as a function-
oriented language.
Before the C language, older languages like BASIC, Fortran, Algol, and Pascal did not provide proper control
statements. These were considered unstructured languages. In contrast, C offers robust control statements
with building blocks using braces {} , making it a well-structured language.
In C, large programs are divided into several modules at the design level, and these modules are
implemented as functions during coding. Ultimately, the entire program becomes a collection of functions.
Therefore, C is often referred to as a function or procedure oriented language.
The main issue with function-oriented languages is that all functions are defined globally. This means that
any function can call any other function from anywhere in the program. As the number of functions
increases in larger projects, managing them becomes increasingly complex. Literally, the C language fails
when the program size exceeds 50,000 lines code.
A program is a collection of data and code. In large programs, data is represented using structures, and code
is represented using functions. In C, both are defined globally, within the global scope. The problem is that
as the number of structures and functions increases, it becomes difficult to determine which data is
processed by which function. This is why C is suitable only for small projects.
Finally, the C language possesses good control statements, allowing us to write code smoothly, but it lacks
design approaches, well suitable for small projects.
C++ was created to support the concept of Object-Oriented Programming (OOP). You may often hear
phrases like "C++ with OOP" or "OOP with C++." OOP is a set of principles and approaches that every
programmer needs to follow. To understand OOP, let's explore it with an example.
Traffic rules and regulations guide the traveller easy to move in complex roads. In this case, traffic systems
or approaches, such as lights, zebra crossings, and dividers, guide travelers to move smoothly.
Similarly, in OOP, there are three main principles or approaches: 'Encapsulation,' 'Polymorphism,' and
'Inheritance. These principles guides or forces the developers to develop application in well planned
manner. These systematic approaches were developed to help designers as well as programmers to write
complex programs easily. These integrate the design and development of code, making it easier for
programmers.
In the C language, there are no specific approaches for writing programs in a systematic way, which can lead
to everyone writing in their own style, creating complexity for others. In OOP, when these approaches are
followed, everyone codes in a uniform style, making the code easier for others to understand and work
with. As it promotes uniform coding, if someone develops a program using the OOP style, others can easily
understand it. This uniform style coding C++ is well suitable for both small and big projects.
OOP ensures that programs are written in a uniform style, which is why it is widely accepted in the
programming world. Finally, OOP makes complex programs easier to design, develop, understand, debug,
modify and extend.
6 Introduction to C++ | C-Family
As a C programmer, you may think, "C++ is an advanced language compared to C." However, that is not
entirely accurate. It is not an advanced version of C but rather an extension of it. C + OOP == C++.
That's why it's called C++ (like an increment of C's value).
This is just an introduction to the OOP concept, and we will explore in depth middle of this book.
However, from the very beginning, this book introduces OOP concepts step by step indirectly.
C++ is a superset or extension of C, meaning all features available in C are supported or adopted by C++.
Additional features have been added to support object-oriented programming (OOP). C++ adopts all the
basic elements from C, such as data types, operators, if statement, if-else statement, loops, arrays,
functions, pointers, strings, structures, etc. Even the syntax of these elements has not been altered.
Therefore, all C programs can be compiled and executed on a C++ compiler.
It’s important to note that before diving into C++, you should have a solid understanding of functions,
pointers, and structures in the C language. Remember, C++ is an extension of C, and your goal is to learn the
additional features of C++. Once you are familiar with C, learning C++ will become more interesting.
This book is designed for those who are proficient in C and want to learn C++. Its focus is on explaining the
internal workings of object-oriented programming with a limited number of examples. The examples
provided are relevant to everyday life, presented in a straightforward way, and the same examples are
repeated to help readers focus on concepts rather than on programs.
Operators
C++ provides some additional operators as an extension to the operators in C. the scope resolution operator
(::), the reference operator (&), the new and delete operators, the i/o insertion-extractor operator (<<,>>),
typeid, explicit, etc. Let us revise some important and very common operators.
Arithmetic Operators + - * / %
Relational Operators < > <= >= == !=
Logical operators && || !
Bitwise Operators & | ^ ~ << >>
Unary Operators + (+ve sign) - (-ve sign) ++ -- & *
Ternary operator ?:
Assignment Operators = += -= *= /= %= &= != ^= <<= >>=
Comma operator (,) Example: a = (b = 3, b + 2);
sizeof Example: sizeof(int), sizeof(float)
Priority 1 () [] -> .
Priority 2 ! ~ +(sign) -(sign) ++ -- (pre incr/decr)
Priority 3 sizeof &(reference) *(de-reference)
Priority 4 * / %
Priority 5 + -
Priority 6 << >>
Priority 7 < <= > >=
Priority 8 == !=
Priority 9 ^ | & ( ORing, ANDing)
Priority 10 && ||
Priority 11 ?: (conditional operator)
Priority 12 = *= /= %= += -= &=
Priority 13 ^= |= <<= >>=
Priority 14 Comma operator (,)
Priority 15 ++ -- (post increment/ decrement)
In the above table, Operators in the same row have the same precedence. Among same precedence
operators, the evaluation takes place from left side to right side in the expression. Only the assignment &
unary operators are performed from right-to-left. eg: a=b=c=d, here first c=d, then b=c , and finally a=b;
8 Introduction to C++ | C-Family
Comma operator(,)
It is used to separate two or more instructions in the program. It is used in several contexts in the
programming. The actual behavior of comma operator is that, it returns the right hand side operand value as
the result of the expression.
a=2, b=3, c=10; // Here comma works as separator
c=a , b; // it is combination of two instructions “c=a and b”, but ‘b’ does nothing
a = (b, c); // it is also a combination of two instructions, “b and a=c”
C++ keywords
Category Keywords
Data Types int, char, float, double, void, bool
Modifiers long, short, signed, unsigned
if, else, switch, case, default, for, while, do, break,
Control Flow
continue, return, goto
Functions & Exception Handling void, return, throw, try, catch
Memory Management new, delete
Access Modifiers public, private, protected
Classes & Inheritance class, struct, union, this, virtual, friend, typename, enum
Token
Consider the expression x + y. This expression consists of three tokens: x, y, and +. Here, x and y are called
operands, while + is called an operator. The compiler breaks down all instructions into individual tokens to
check for syntax errors. This process of splitting expressions into tokens and checking them is known as
parsing. A token can be defined as a fundamental element in a program that is parsed by the compiler.
Tokens can include keywords, operators, identifiers, constants, or other symbols. For example
a+b // this expression has 3 tokens: a , b , +
a<=b // this has 3 tokens ‘a’, ‘b’, ‘<=’ ( here ‘<=’ is a single token )
c++ // this has 2 tokens c , ++ ( here ‘++’ is a single token )
if(a<b) // this has 6 tokens
note: the symbol ‘+’ is different from ‘++’ , both are different operators.
10 Introduction to C++ | C-Family
These comment lines are ignored (skipped) during the compilation of a program and are not executed.
Comments are not part of the program, used for documentation purposes.
C comments can be used for both single and multiple lines, while C++ supports only single line.
Operating System
The term O.S refers to a set of programs that manage the resources of a computer. The resources of a
computer include the processor, main memory, disks, and other devices such as the keyboard, monitor, and
printer that are connected to it. The operating system also provides a user-friendly interface, allowing users
to operate the computer without needing to know the details of the hardware. Thus, the interface conceals
the underlying workings of the computer. The main functions of an operating system include memory
management, process management, disk management, I/O management, security, and providing an
interface for the user, among others.
The most widely used operating systems are MS-DOS, UNIX, and WINDOWS. DOS is a simple operating
system that was primarily used on PCs in the past. UNIX, Linux, Mac, and Windows are used across a variety
of computers, including mainframes, servers, graphics workstations, supercomputers, and also PCs.
Nowadays, Windows and Linux are primarily used in workstations and PCs.
When a user runs a program (app) on the computer, the operating system loads the program into main
memory (RAM) from the hard disk and then executes it instruction by instruction with the help of the
processor. The processor can take and execute only one instruction at a time. Thus, this loading and
execution of instructions is done under the control of the OS. The OS is primarily responsible for managing
these tasks and also ensures that the computer can perform other operations.
The relation between hardware, operating system, user-program, and user can simulate with a banking-
system such as bank, employee, transaction and customer. The hardware as a bank and O.S as a bank
employee, who works dedicatedly to organize all transactions of a bank, whereas the user as a customer and
user-program as a transaction, the user submits his program just by giving a command to the computer; the
responder, the O.S, takes up the program into main memory and process the instructions on the hardware
under its control. The following picture shows the layers of interaction between user and the computer.
User Customer
User program Transaction
Operating system Bank employee
Computer hardwar Bank
In this way operating system is the total responsible for every task which is performed in the computer.
The world biggest software are nothing but operating systems like windows, unix, anroid, linux.
12 Introduction to C++ | C-Family
This return value is stored in the operating system log files (history files) for further reference or feedback. In
C, we have used void main() instead of int main() in simple programs and educational programs, where the
return value is not considered important. However in critical system programing the “int main()” is the
mandatory.
The CodeBlocks IDE is available along with cpp compiler in the internet, google throw the keywords:
“Download codeblocks-10.05mingw-setup.exe” , the best download site is: https://sourceforge.net.
The C++ compiler can also function as a C compiler. If you save your program with the file extension ‘.c’,
it will be compiled as a C program. If you save it with the extension ‘.cpp’, it will be compiled as a C++
program.
We can use C language libraries in C++, such as printf(), scanf(), pow(), and sqrt(). In C++, there are special
I/O functions for reading values from the keyboard and printing values on the screen. These I/O functions
are introduced in the middle of this book; until then, we have used printf() and scanf() because they are
often considered more sophisticated than the standard C++ I/O.
13 Introduction to C++ | C-Family
Type casting
Process of converting a value from one type to another type is called as type casting. In C, the type casting is
done in two ways. ①Implicit type casting (automatic casting) ②Explicit type casting (manual casting)
eg1: 10.5 + 20; // here the value 20 will be converted into 20.00 by the compiler implicitly
eg2: 10 * 20.00; // here the value 10 will be converted into 10.00 by the compiler implicitly
eg5: int x;
float y=29.34;
x=y; // Here the integer part of ‘y’ value 29 is assigned to ‘x’ ( fraction bits will be truncated/omitted )
In the expression K=10+X*Y, the product of X*Y is first calculated and stored in a temporary variable before
being added to 10. This temporary variable is a nameless variable automatically created by the compiler
(let's call it T). Then the instruction K=10+X*Y is executed as T=X*Y; K=10+T; Here, X Y are of type int, so T
will also be of type int. However, if the result of X*Y exceeds the range of an int, it cannot be stored in T,
causing a loss of some bits.
The solution is to write the expression as K = 10 + (long int)X*Y. Here, we explicitly convert X to long int, and
the compiler converts b, making T as long int, which can store the result of X*Y.
Changing a lower type to a higher type is called promotion, while the reverse is called demotion.
15 Introduction to C++ | C-Family
character constants
To specify a character constant, we must enclose the character within the pair of single quotes.
eg. ‘A’ ‘z’ ‘s’ ‘8’ ‘+’ ‘;’ etc
string constants
It is a collection of characters enclosed within double quotes, used to represent names, codes, abels, etc.
eg: “Hello! Good morning!” “Magic mania” “A” “123” “A1” “#40-5-8A” “C-Family”
16 Introduction to C++ | C-Family
float constants (Real numbers)
We can specify the real numbers in two different notations, namely general and scientific notation.
Here the format string ‘f’ is attached at the end of value.
In normal representation: 3.1412f -25.62f 98.12f -045632.0f 1.f 9.13f
In scientific exponential representation: the syntax is [-]d.dddde[+/-]ddd where d is any digit.
2 . 32e5f (means 2.32 x 10^5 i.e. 232000.0)
12 . 102e-3f (means 12.102 x 10^-3 i.e., 0.012102)
-2 . 165e6f (means -2.165 x 10^6 i.e., -2165000.0)
3 . 68e3f (means 3.68 x 10^3 i.e., 3680.0)
double constants: This is the default type for real numbers (floating point values).
eg: 1.2 45.3 4.39393 349.34899034
45.4e15 44.54e4 (‘l’ or ‘L’ is option for double)
long double: for the long double, the format string ‘l’ or ‘L’ is used.
eg: 3.14L
314.41 (Equivalent to 314. 0L)
3.68e3L (Means 3.68 x 103 i.e., 3680.0L)
17 Migrating C to C++ | C-Family
Code to find single Circle object Code to find two Circle objects
void main() void main()
{ float radius, area, perimeter; { float radius1, radius2, area1, area2, peri1, peri2;
printf(“enter radius::”); printf(“enter radius1 & radius2::”);
scanf(“%f”, &radius); scanf(“%f%f”, &radius1, &radius2);
area=3.14*radius*radius; area1=3.14*radius1*radius1;
perimeter=2*3.14*radius; area2=3.14*radius2*radius2;
printf(“area is %f “, area); ------------
printf(“ perimeter is %f ”, perimeter ); ------------
} }
The first program works fine when we want to find the area and perimeter for a single circle. However,
when we want to find the values for two circles, as shown in the second example, the code becomes
complex and harder to read. If we need to find the area and perimeter for three circles or an array of circles,
the code becomes even more complicated and unreadable.
When the number of input circles changes, the entire code needs to be modified. This means that the code
has to be rewritten whenever the input data size changes. However, by using functions, pointers, arrays, and
structures, we can simplify the code. Once the code is written using these features, it doesn't need to be
changed, regardless of the number of input circles. This allows the code to remain flexible and scalable
without requiring modifications as the number of circles increases.
Here, the code is divided into two parts. Part1 defines how to process a single circle object, and this code
can be reused for any number of circles. Part2 defines the main() function, where Part1 is applied based on
the input size. This is shown below.
Part1 Part2
struct Circle The main() fn for calculating single circle
{ float radius, area, perimeter; void main()
}; { struct Circle k;
void scan( struct Circle *p) scan( &k );
{ printf(“enter radius ::”); find( &k );
scanf(“%f”, &p->radius); print( &k );
} }
void find( struct Circle *p) -----------------------------------------------------------------
{ p->area = 3.14 * p->radius * p->radius; The main() fn for calculating two Circles data.
p->perimeter = 2* 3.14 * p->radius; void main()
} { struct Circle k1, k2;
void print( struct Circle *p) scan( &k1 ); scan( &k2 );
{ printf(“area is %f”, p->area); find( &k1 ); find( &k2 );
printf(“perimeter is %f”, p->perimeter); print( &k1); print( &k2 );
} }
18 Migrating C to C++ | C-Family
U might have observed the above code that, even though the number of input circle objects changes, the
part1 code remains the same without any modifications. Generally, in a development environment, part1 is
written by some ‘X’ person and part2 code by some ‘Y’ person(user). part1 code defines generic code which
works for single or multiple objects.
Here part1 code gives an idea how to write an independent, reusable, modifiable and expandable code
without affecting the part2 code. Part1 code works like API/Libraries in our project. In this way, using
functions, pointers and structures, we can write independent simplified reusable code. Part1 of the code is
created by senior industry experts, while part2 is developed by the next group of developers according to
the project's requirements. The part2 people are also called developers or users.
----------------------------------------------------------------------------------------------------------------------------------------------
Comparing two Dates
Let us have one more example: scanning two dates and finding both are equal or not
void main()
{ int d1,m1,y1, d2,m2,y2;
printf(“enter date1::”);
scanf(“%d%d%d”, &d1, &m1, &y1);
printf(“enter date2::”);
scanf(“%d%d%d”, &d2, &m2, &y2);
if( d1==d2 && m1==m2 && y1==y2 )
printf(“equal”);
else printf(“not equal”);
}
Here, the code is fine for comparing two dates, but if there are three or more input dates, the code needs to
be changed, and it becomes more complex. Like above program, if we use functions, pointer and structures
then we get following simplified code
Part1 Part2
struct Date Comparing 2 dates
{ int d, m, y; void main()
}; { struct Date a , b;
scan( &a );
void scan( struct Date *p ) scan( &b );
{ printf(“enter date ::”); k=compare( a , b );
scanf(“%d%d%d”, &p->d, &p->m, &p->y); if ( k == 1) printf(“ equal”);
} else printf(“ not equal”);
}
int compare( struct Date p , struct Date q ) -------------------------------------------
{ if( p.d==q.d && p.m==q.m && p.y==q.y) Comparing 3 dates
return 1; struct Date a, b, c;
else return 0; --------------
} k = compare( a , b );
if( k==1) // if a,b are equal then compare b,c
k=compare( b , c );
if ( k == 1) printf(“all are equal ”);
else printf(“ all are not equal ”);
19 Migrating C to C++ | C-Family
Again, in the above code you might have observed that, the part1 code remains unchanged regardless of
whether the number of dates to be compared is 2 or 3. This demonstrates how we can write independent
and reusable code using functions.
----------------------------------------------------------------------------------------------------------------------------------------------
Adding two times
Let’s consider an example of finding the addition of two times, such as the total hours worked by an
employee in two shifts. We’ll use functions and structures to handle this in a clean and reusable way.
Yes, by observing the above programs, it's clear that using functions, pointers, structures significantly
improves code independency, simplicity, reusability, and modifiability. This approach makes it easier to
manage, understand, and extend the code. Let us migrate to C++;
C++ is a superset of C, meaning it was built upon C language features. C++ is not an advanced language;
it is merely an extension of C. All the concepts of C can be used in C++ without any thought, such as data
types, control structures, arrays, functions, pointers, structures, etc.
All C programs can be compiled using a C++ compiler without any modifications. In C++, extra features were
added without disturbing existing C language features. For example, bool as a data type, new/delete for
dynamic memory allocation, and cin/cout for input/output, etc. We will discuss C++ features in the
upcoming chapters.
In C++, we use the ‘class’ data type in place of ‘struct’ data type. The ‘class’ is more sophisticated than struct.
In structures, we define only data members, but their manipulation functions should be written outside the
structure block. This is because the structure syntax was designed in that way. However, in a class, both the
data and its manipulation functions are written inside the class block.
20 Migrating C to C++ | C-Family
The following example shows the addition of two numbers and demonstrates how to write the code in C++
using a 'class' instead of a 'struct'. Remember, in C++, we place data members and their manipulation
functions inside the class block.
Part1 Part2
class Adder The main() fn for showing sum of two numbers
{ int a, b, total; void main()
void set() { class Adder k;
{ a=10; k.set( );
b=20; k.find( );
} k.print( );
void find() }
{ total=a+b;
}
void print()
{ printf(“%d %d %d ”, a , b, total );
}
};
There's no doubt that a 'class' is more sophisticated than a structure; it offers superior syntax and additional
features. In this chapter, we will briefly discuss the 'class' and the 'this' pointer. In the following chapters, we
will dive deeper into classes and their syntax.
21 Migrating C to C++ | C-Family
I want to reveal an important fact about the C++ compiler: every C++ program is ultimately converted
into C-like code by the compiler because C is a native language that closely resembles machine code.
Therefore, any programming language code is eventually converted into C-like code. Let's see how the
above C++ code converts into C code (the exact code may vary).
Here, the class keyword is effectively converted into the struct keyword as shown above.
The call statement k.set() is converted into set(&k).
The call statement k.find() is converted into find(&k).
In this process, ‘&k’ is passed as an argument to the function by the compiler. Within the function body,
the receiving parameter ‘this’ is used. The ‘this’ pointer is a hidden pointer created by the compiler to
hold or receive ‘&k’. Using the ‘this’ pointer, the members of the structure or class are accessed as
shown in the above example.
22 Migrating C to C++ | C-Family
Following program finds area and perimeter of a given circle, this explains how ‘this’
works in the program
finding radius of circle C++ Code C code after converting From C++
class Circle struct Circle
{ { float radius, area, perimeter;
float radius, area, perimeter; };
Time add( Time b) struct Time add( struct Time *this , struct Time b)
{ long int k; Time t; { int k; struct Time t;
k=(h+b.h)*3600 + (m+b.m)*60 + (s+b.s); k=(this->h+b.h)*3600 + (this->m+b.m)*60 + …. );
t.h=k/3600; t.h=k/3600;
t.m=(k%3600)/60; t.m=(k%3600)/60;
t.s=(k%3600)%60; t.s=(k%3600)%60;
return t; return t;
} }
int compare( class Date q ) int compare(struct Date *this , struct Date q)
{ if( d==q.d && m==q.m && y==q.y ) { if( this->d==q.d && this->m==q.m && this->y==q.y)
return 1; return 1;
else return 0; else return 0;
} }
};
1. The aim of a class is to provide the programmer with a tool for creating new types that can be used as
conveniently as built-in types. Of course, this is similar to a structure in C, but here the data and its
manipulation functions are packed and tied together as a single unit.
2. When we define a new class in the program, it means we have added a new data type to our program.
This can be used in the same way as int and float types. In the above example, the class definition
‘Adder’ works as a blue-print of our-type. So the word ‘Adder’ can be used like int & float types in our
program.
3. Now we can declare variables of a class like: Adder ob1, ob2; ( this is like: int p , q; )
So, variables of a class are declared just like any other variables in the program.
4. Class variables are called objects. The creation of memory space for objects is the same as for structure
variables in C. The following example explains how memory space for objects is created in the program.
Class Adder Here how ob1 & ob2 are created in memory
{ int x, y, total;
void scan() { …. } ob1
void find() { …. }
void print() { …. } x y total
};
ob2
int main()
{ int a,b ; // here a,b are int-type variables x y total
Adder ob1, ob2; // here ob1,ob2 are class-type variables
--------------
--------------
}
26 class and object | C-Family
5. The class declaration specifies the name of the class, the list of data members, and the functions that will
operate on the class data. The space for data members is created in the object, not at the class
declaration. Many people confuse this, so let us look at the following example.
Example
class Adder
{ int x=100
int y=200; error, we cannot assign values to x, y,
int total=x+y; because here space will not be created for x,y.
void scan() { …. }
void find() { …. }
void print() { …. }
};
int main()
{ Adder ob; // here space for x,y creates in the ‘ob’,
ob
// so we can store values to x,y like structures in C.
ob.x=100; ob.x ob.y ob.total
ob.y=200;
---------
}
6. The class declaration is treated as a building plan (blueprint), whereas an object is treated as the
constructed building based on that plan. The comparison of 'class vs object' is often compared to
'building plan vs building’.
7. class declaration defines the logical view at conceptual level of our type about data properties and
functional behavior. Therefore it is often called template or blueprint. In contrast, an object is the
physical instance of a class. A class does not occupy any physical memory space in the executable file of
machine code; only the object occupies physical memory in the executable. Thus, a class is considered a
logical entity, whereas an object is considered a physical entity.
8. Finally, we can conclude that a class is a data type, whereas an object is a variable of the class type.
So, a class is a concept, model, or template that defines how an object should be. An object is the
physical implementation of a class and is also called an instance of a class.
9. We can create as many objects as we want using a class. Each object is said to be an instance of the class.
In programming, we first define the class body and then create objects from it. It is similar to defining a
building plan before constructing a building.
10. Why class variables are called objects? In the real world, things like a fan, pen, chair, bottle, dog,
human, etc., are called objects. Every object has its own shape and benefits. In general, an object can be
defined as a collection of data properties with functionality. For example, a pen is an object with data
properties like color, cost, weight, and length, and functionalities like writing, drawing, and marking.
Similarly, a fan is an object with data properties like color, cost, and length, and functionalities like
circulating air, clearing dust, and cooling/drying objects. In this way, every object has its own unique
shape's data properties, and functional uses. Similarly, a class object contains data and functional
properties; therefore, it is called an object
11. The variables that are declared inside the class-block are called data-members (here x, y, total) and
functions that are defined inside the class block are called member-functions.
12. The member-functions manipulate the data-members such as scanning, processing, and printing.
13. In c++, the class is the backbone, and the entire program code orbits around classes. A C program is
made up of a collection of functions, whereas a C++ program is made up of a collection of classes.
27 class and object | C-Family
Syntax of class
the syntax of a class is the same as the syntax of a structure, but we write the functions inside the class
body. Additionally, access modifiers like private/public are used.
1. The variables that are declared inside the class are called data-members (here x, y, total) and functions
that are defined inside the class block are called member-functions.
2. The member-functions manipulate the data-members such as scanning, processing, and printing.
3. Private members cannot be accessed outside the class-block.
4. Private members can be accessed only by other private and public functions of the same class.
5. This private access concept is same as local variable in functions.
6. In contrast, if any member need not be accessed outside the class block, we declare it as private.
This feature greatly reduces the complexity of the variables and also avoids misuse.
7. This is the default access type. If no access type is specified, the compiler assumes it to be private.
8. Public members can be accessed inside & outside class block (anywhere in the program).
This is like global variable in a C program.
9. The members of object are accessed just as structure variables in C. Here two operators are used
1. selection operator( . ) 2. pointer selection operator( -> )
The expression 'ob.x' accesses the 'x' value in 'ob'.
The expression ‘ob.y’ accesses the ‘y’ value in the ‘ob’.
For example filling values to ‘ob’ as
ob.x=100;
ob.y=200; p ob
12. Functions within a class are called member functions. Only one copy of each member function exists for
all objects, and all objects are linked to the same functions. Many people mistakenly believe that each
object contains its own set of data and set of functions. In reality, each object has its own set of data but
not own set of functions; only one copy of each member function exists and is shared among all objects.
This means that all objects are linked to (or share) the same member functions in the program.
The following example explains this.
class in c++
class Adder
{ private: int main()
Int x, y, total; { Adder ob1, ob2 ;
public: ob1.scan();
void scan() ob2.scan();
{ printf(“enter two values :”);
scanf(“%d%d”, &x, &y);
}
ob1.find();
void find() ob2.find();
{ total=x+y;
}
ob1.prin();
void print() ob2.print();
{ printf(“total=%d “, total); }
}
};
The instruction ‘ob1.scan()’ is simply a function call with the object ob1. This is similar to calling a function in
the C language. The compiler implicitly interprets this call as scan(&ob1). Therefore, the address of ob1 is
implicitly passed as an argument to the function and stored in a hidden pointer called ‘this’. Using the ‘this’
pointer, the data members of ob1 are accessed as this->idno, this->m1, this->m2 within the function body.
(we have already seen about the this pointer in previous chapter)
Similarly, the function call ob2.scan() is interpreted as scan(&ob2), where the address of ob2 is passed and
stored in the same this pointer. Using the ‘this’ pointer, the data members of ob2 are accessed.
29 class and object | C-Family
Here, Y is public, so it can be accessed anywhere in the program. The instruction ob.Y=200 at main() fn will
not produce any error. Private reduces the variables complexity and also increases the security like function
local variables in C. Within a class, any member function can access any other member, regardless of its
public or private access modifier.
Generally, in real-world applications, most data members in a class are declared as private, while most
member functions are declared as public. Typically, around 90% of data members are private, while about
90% of member functions are public. This is a common pattern in the industry, although it may sometimes
vary.
----------------------------------------------------------------------------------------------------------------------------------------------------------
30 class and object | C-Family
ob
day, month, year
set () find() compare() print() get()
31 class and object | C-Family
get() function
In some cases, private member values need to be read from outside the class, where we write a get()
function with public access. This function is used to get/return the values of private data members of the
class. The get() function works opposite to the set() function. The set() function sets the value to the data
member, whereas the get() function returns the current value of the data member. For example
From previous knowledge, the data members of a class are managed through member functions, for
example, set(), print(), process(), etc. So, the data members need not be accessed or should not be accessed
directly from outside the class. Hence, it is better to place them in the private section to avoid misuse from
other parts of the program (other parts meaning from main() function, child class, or other classes). In case
there is a need to read/write private variable values from outside, this can be achieved through these set()
and get() functions. These functions are often called setters and getters. Remember, these functions are not
only used to read/write but also to perform validations.
Example2:
Generally, if a set() function is written for a particular member, its name is setXXX(), where XXX is the
member name. For example, setIdno(), setName(), setMarks(), etc. The first letter of the member name
should be capitalized. Similarly, get() functions follow the same rules as set().
class Student
#include<stdio.h> { private: int idno , marks;
void main() public:
{ Student ob; int getIdno( ) // returns idno of student
ob.setIdno(10); { return idno;
ob.setName(“Srihari”); }
printf(“%d%s“,ob.getIdno(),b.getMarks()); void setIdno(int idno) // to change idno of student
} { this->idno=idno;
}
int getMarks( ) // returns marks of student
{ return marks;
}
void setMarks( int marks )
{ this->marks=marks;
}
};
33 class and object | C-Family
class Sample
{ public:
void show() // member-function
{ printf(“hello”);
}
};
void show() // non-member-function ( it is a C language function )
{ printf(“world”);
}
int main()
{ Sample ob;
ob.show(); // hello
show(); // world
}
-----------------------------------------------------------------------------------------------------------------------------------------------
Sometimes class and its functions body used to write in separate files. Let us following example
34 class and object | C-Family
We know, the data members are accessed/managed through member functions of that class, for example,
set(), get(), process(), find(), increment(), add(), print(), etc. So the data members need not be accessed
directly from outside class like ob.day, ob.month, ob.year at main() fn. So these members are kept in private
section as they need not be accessed outside class.
In case, if any member value need to be read/write directly from outside, then we achieve through set() and
get(). Taking member as public or private is up to you, this is just access modifier not compulsion.
Some data members constants, static members, static constants are declared mostly in public.
Most of the member functions are declared in public as they have to call from outside class. These works as
controlled interface to the class data. (That is, we access or control objects through these functions)
Some member functions can be private as they need not be accessed from outside class.
These private functions are accessed by only others functions of same class.
In development environments, many people may involve while coding projects. Generally, total project is
divided into several modules, where each module is made up of with several classes. Different classes may
be written by different people.
For simplicity, let's assume two people are working on our code examples provided in this book. In our code
examples, let the class be written by person X, and the main() function be written by person Y. The
person ‘X’ hides the data members to ‘Y’ by keeping in private section. From the main() function, the person
‘Y’ access/manipulate through public interface functions like set(), get(), process(), print(), etc. So, the
person Y needs not to know the names and types of data members used by person X in the class.
If X changes the class data members, such as by changing their names, types, or logic, there is no need to
35 class and object | C-Family
modify the code in the main() function( it does not affects the code in main() fn). Sometimes, X can add
extra functionality to the class without disturbing other part of code.
36 class and object | C-Family
37 Programs list | C-Family
Let us see some sample program, how they constructed in C++ using classes
and objects.
The following program finds the total count of boys & girls in two schools. The set() assigns sample input
values to the objects ob1 and ob2. Later, these values are added by gender wise to ob3 and printed.
#include<stdio.h>
class School
{ int boys , girls; // default is private int main()
public: { School ob1,ob2,ob3; // object of two schools
void set(int boys, int girls) ob1.set(10,20);
{ this->boys=boys; ob2.set(30,40);
this->girls=girls; ob3=ob1.add(ob2);
} ob3.show();
School add(School ob2) }
{ School t;
ob1 ob2
t.boys=boys+ob2.boys;
10 12 20 22
t.girls=girls+ob2.girls;
boys girls boys girls
return t;
}
void show() ob3
{ printf("\n boys = %d", boys); 30 32
printf("\n girls = %d", girls); boys girls
}
};
In this program, we set two sample input date values to object1 and object2 using the set() function in
the main() function. Later, we compare the two dates and print whether they are equal.
The following program adds two time durations and prints the total time on the screen.
The two durations represent the employee's work time across two shifts in the office.
#include<stdio.h>
class Time
{ int h,m,s; int main()
public: { Time ob1, ob2, ob3;
void set(int h,int m,int s) ob1.set(3,30,40);
{ this->h=h; ob2.set(4,50,50);
this->m=m; ob3=ob1.add(ob2);
this->s=s; ob3.show();
} }
Time add( Time ob2)
{ Time t; int n;
n=(h+ob2.h)*3600+(m+ob2.m)*60
+(s+ob2.s);
t.h=n/3600;
t.m=(n%3600)/60;
t.s=(n%3600)%60;
return t;
}
void show()
{ printf("%d:%d:%d",h,m,s);
}
};
The following program adds points to a player's score. Initially, the score is set to 0.
Points are then added to the score, and the final total is printed on the screen.
#include<stdio.h>
class Player int main()
{ int score; { Player ob;
public: ob.set(0);
void set( int score ) ob.addScore(10);
{ this->score=score; ob.addScore(20);
} ob.show();
void addScore( int score ) }
{ this->score+=score;
}
void show()
{ printf("player score is %d", score );
}
};
39 Programs list | C-Family
The following add() function in the String class concatenates two string objects and returns the result.
Initially, we assign two sample strings, 'hello' and 'world,' to object1 and object2.
We use a static array char a[100] to store the input string. Let's take a look at the program below.
#include<stdio.h>
#include<string.h> int main()
class String { String ob1,ob2,ob3;
{ char a[100];
public: ob1.set("hello ");
void set( char str[] ) ob2.set(" world");
{ strcpy( a , str ); ob3=ob1.add(ob2);
}
String add( char str[]) ob3.show(); hello world
{ String t; ob3=ob1.add(" hi ");
strcpy( t.a , a ); ob3.show(); hello hi
strcat( t.a , str ); }
return t;
}
String add( String ob2)
{ String t;
strcpy( t.a , a );
strcat( t.a , ob2.a );
return t;
}
void show()
{ printf("\noutput is:%s", a );
}
};
The following program adds seconds to a given time and maintains AM/PM to specify morning or
evening. For example 11:40:50 PM + 2 hours 1 : 40 : 50 : AM
Function overloading
In the C language, we can’t give the same name to more than one function, where, every function carries
unique function name. However, in C++, the same name can be given to two or more functions but their
parameters should be different. Writing more than one function with the same name with different
parameters is said to be function over-loading. Based on the arguments and parameters, the function-call
statements are linked with the suitable function-body as shown below example.
int add( int a, int b )
{ return a+b;
}
float add( float a , float b )
{ return a+b;
}
int main()
{ int x=add(10,20);
printf(“%d “ , x );
float y=add(10.64F , 20.54F);
printf(“%f“ , y );
}
Here the function name is same for both functions, but their parameters are different, based on the
arguments and parameters, the function-call statements are linked with the function-body.
----------------------------------------------------------------------------------------------------------------------------------------------
Example2: in the following code, the function name “add()” is used to find addition of 2 and 3 integers and
also finds the float addition.
int add( int a, int b )
{ return a+b;
}
int main()
{ int x; float y;
x=add(10,20);
printf(“%d “ , x );
x=add(10,20,30);
printf(“%d“ , x );
y=add(10.55F, 34.34F);
}
note: functions are differentiated based on parameters but not on return-type.
----------------------------------------------------------------------------------------------------------------------------------------------
42 function overloading | C-Family
Following example finds reverse of an integer and a string.
int reverse( int n )
{ int rev=0;
while( n>0 )
{ rev=rev*10 + n%10;
n=n/10;
}
return rev;
}
char* reverse( char *str )
{ int I , j; char t;
for(j=0; str*j+!=’\0’; j++) // this loop finds length of string.
{
}
for( j--, i=0; i<j; i++, j--) // this loop is to reverse the string;
{ t=str[i]; str[i]=str[j]; str[j]=t;
}
return str;
}
int main()
{ printf(“reverse of 123 is %d“ , reverse(123) ); // this calls first version
printf(“reverse of hello is %s”, reverse(“hello”) ); // this calls second version
}
----------------------------------------------------------------------------------------------------------------------------------------------
Rules for function overloading in C++
1. All functions must have same name.
2. All functions parameters must be different as per count or types.
3. All functions must be present within a scope (sometimes in parent-class and child-class)
4. Functions are differentiated based on parameters but not on return-type.
5. Ambiguity error: If a function call can match more than one overloaded version equally well, the compiler
will generate an ambiguity error. Overloading must be designed to avoid such conflicts. For example
#include<stdio.h>
int add(float a, float b) Both functions are suitable for the call statement
{ return a+b; add(65,66), but the compiler is unable to determine
}
which one to call, resulting in ambiguity. The integer
char add(char a, char b)
{ return a+b; values 65 and 66 can also be interpreted as the ASCII
} values of 'A' and 'B', which contributes to the ambiguity
int main() error. To resolve this, we need to address the ambiguity
{ int k; manually.
k=add(65,66);
}
43 default arguments | C-Family
Default arguments
in some cases, some arguments can be omitted when calling a function; in this case, the compiler substitutes
default arguments in their place. Basically, default arguments are sample or initial values specified during
making of function body. These can be taken as alternative values for parameters when the user omitted
some arguments while calling a function. For parameterized functions, the same number of arguments must
be passed as the parameter count. So, if the caller omitted such arguments, then compiler substitutes
default values in their place. This feature eliminates the need for writing too many overloaded functions and
also simplifies the logic and code. These arguments must be specified from right to left in the function
prototype or definition. Consider the following example
void show( int a , int b=20 ) // here ‘b’ is the default argument, the default value is 20.
{ printf(“\n%d %d” , a , b);
}
void main()
{ show( 100 , 200 );
nd
show( 100 ); // here default value 20 substitutes as 2 argument, this call converted as “show(100,20)”
}
output: 100 200
100 20
As we know, we should pass two arguments to the show() function. However, in the second call, show(100)
has only one argument; therefore, the compiler substitutes the default argument 20 as the second
argument. This call will be replaced as show(100, 20);
---------------------------------------------------------------------------------------------------------------------------------------------------------
Example2:
void show( int a=10 , int b=20 ) // both parameters has default values
{ printf(“\n%d %d” , a , b);
}
void main()
{ show( 100 , 200 );
show( 100); // this call will be replaced to: show(100 , 20)
show(); // this call will be replaced to: show(10 , 20);
}
output: 100 200
100 20
10 20
----------------------------------------------------------------------------------------------------------------------------------------------
Let us have some valid and invalid declarations
void show(int a, int b=0); // valid
void show(int a=10, int b); // in-valid, default should be given from right-to-left (without ‘b’ , ‘a’ can’t be default)
void show(int a, int b=0, int c); // in-valid, default should be given from right-to-left
void show(int a=10, int b=0, int c); // in-valid, default should be given from right-to-left
void show(int a=10, int b=20) // valid
void show( int a , int b=0 ); // function proto-type with default arguments
void main()
{ show( 100 , 200 );
show( 100 ); // here default argument 0 is assigned to ‘b’
}
void show(int a, int b) // don’t repeat the default arguments here, already we have given at proto-type.
{ printf(“\n%d %d” , a , b);
}
output: 100 200
100 0
remember: Default arguments should not be given in both places (at proto-type & at function–body).
-----------------------------------------------------------------------------------------------------------------------------------------------
inline function
Inline function is a simple function having one or two lines limited code in its body. It is just like macro
function in C. To make any function as inline, we need to add keyword ‘inline’ before function name.
For example:
inline int add( int a , int b )
{ return a+b;
}
If any function is line, then compiler substitutes function’s code at every call statement which appears in the
program. That is, it replaces all call statements by its code of function, so that, it avoids overhead of function
call, function return, creating and destroying of local variables and parameters. Main purpose of inline is to
increase the performance of programs by elimination function calls.
Generally, if any function is called, then control transfers from calling-function to called-function, where it
creates parameters and local variables, after finishing execution of function body, these variables will be
destroyed. After destroying all variables and parameters the control returns to calling-function.
Here, for simple functions, this task of transferring the control, creating-destroying variables and returning
the control between functions dominates the function task. For this problem, the solution is inline function.
Here body substitutes at every call statement.
After compilation, the code can be imagined as
inline int findSum( int x , int y )
{ return x+y;
} void main()
void main() { int k; Observe here, this call statement
{ int k; replaced by its code of function
k = findSum( 10 , 20 ); k = 10 + 20 ;
printf(“output is %d”, k ); printf(“output is %d”, k );
} }
1) In c++, member function’s body can be written inside and outside of class-body
2) If function body presented inside class-body, then compiler automatically takes them as inline, so here
the keyword inline is optional for all functions which appears inside class body. Remember, ‘the code
must be in one or two lines’. If more lines of code presented then compiler takes them as normal
function. The keyword inline is not a command, just a request to the compiler. Let us have one example,
class Sample
{ int add( int a , int b ) // as function body written inside class body, compiler automatically takes as inline function
{ return a+b;
}
int findBig(int a,int b) // here compiler tries to take as inline, but as body having more lines, so takes as normal fn.
{ if( a>b) return a;
else return b;
}
};
3) If function body is presented outside of class, we need add ‘inline’ keyword explicitly before the function
name. In this case, the body must also be limited to one or two lines of code; otherwise, the compiler
will treat it as a normal function, even if it is declared as inline.
46 default arguments | C-Family
4) Remember, the inline feature can be applied to normal functions as well as class member functions.
Let us see following example, where function body has written outside
class Sample
{ int add( int a , int b);
int findBig( int a, int b);
};
inline int Sample::add( int a , int b) // we need to add inline keyword explicitly as body written outside class.
{ return a+b; // otherwise takes as normal function.
}
inline int Sample::findBig( int a , int b) // though declared as inline, but compiler takes as normal function.
{ if( a>b) // because, the code having more lines
return a;
else return b;
}
Suggestion: Just add inline for all functions with code consisting of one or two lines. Don’t worry about
whether the function body is inside or outside the class block.
Actually, this feature could have been managed by the compiler rather than being provided explicitly in C++
---------------------------------------------------------------------------------------------------------------------------------------------
47 Friend Functions | C-Family
Friend class
Like a friend function, we can make one class a friend of another class, so that it can access all private
members of that class. If class-A is a friend to class-B, then class-B can access all private members of class-A.
Let us see the following example.
#include <stdio.h>
class B; // this is forward declaration of class-B , like function-proto-type;
class A
{ private: int x , y;
friend class B;
};
class B
{ public:
void show()
{ A p;
p.x=10; // now class-B can access private members of class-A
p.y=20;
printf(" %d %d " , p.x , p.y ) ;
}
};
int main()
{ B ob;
ob.show();
}
Here, class-A is telling the compiler that class-B is its friend, so the compiler allows class-B to access
class-A's private members. These types of applications are used very rarely.
49 C++ reference operator | C-Family
a p
a
10 2000
10 P
2000 4000
When the original variable is available within a function, creating a reference variable is unnecessary.
This example is for demonstration purposes only. The following example illustrates how the reference
operator is used in call-by-reference.
50 C++ reference operator | C-Family
when swap() fn calls, the arguments(&a,&b) are assigned to when swap() fn is called, the arguments (a,b) are assigned to
parameters (p,q) as: int *p=&a , int *q=&b; parameters (p,q) as: int &p=a , int &q=b;
Returning reference
Returning reference is also possible, but it should not be a function local variable. Let us see following
example
#include<iostream>
using namespace std;
int a , b;
int& getBig()
{ if( a>b)
return a; // reference is returning to main() function
else
return b;
}
int main()
{ printf("enter two values:");
scanf(“%d%d”, &a, &b);
getBig()=1000; // the big value modified to 1000
printf(“%d %d”, a, b);
}
--------------------------------------------------------------------------------------------------------------------------------------------------------
We can’t return reference of a local variable because it will be deleted while returning control to main() fn.
so we can’t create non existing variable’s reference. Following program shows compile time error.
int& test()
{ int a=100;
return(&a); // fatal error. ‘a’ will be deleted while returning control , so we can’t return reference of local variable.
}
void main()
{ printf("%d ", test() );
}
------------------------------------------------------------------------------------------------------------------------------------------------
51 C++ reference operator | C-Family
Here before returning a+b value to main() function, the compiler stores the a+b value into a temporary
variable. Actually, temporary is a nameless variable created & destroyed by the compiler. For a while, let us
say its name is 'temp'. The data type of ‘temp’ is depends upon a+b value-type. The above function can be
imagined with ‘temp’ as:
Compiler creates 206 bytes for int a, b, c[100], d. It adds extra instructions for allocation & de-allocation of
memory as shown above. [ It creates memory in stack as stack.push(206) and stack.pop(206) ]
The static allocation system is much suitable when we know the size of data like employee-name(30 chars),
address(50 chars), pin-code(4bytes for int), phone-number(4bytes for int ),…
This DMA system provides us to create, expand, reduce, or even destroy the memory at runtime. This
feature is very much useful for efficient memory management especially while handling huge collection of
data using ‘data structures’. For example arrays, lists, stacks, queues, trees, graphs, etc. To work with this
feature, C++ provides two operator keywords “new and delete“.
Before going to new & delete operators, first we will learn difference between operator and a function.
Operator is an inbuilt task of compiler whereas function is an outside task from the compiler. Most of the
time, operator is a symbol which is associated with some task. For example, the operators are + - * < > = etc.
The operation “10+20” directly supported by compiler and no header file to be included to support this task.
54 C++ DMA | C-Family
Here compiler generates necessary machine instructions for adding these 10+20 values. Operators are
having simple syntax, easy to use, provide compile time error checking, and also no header files to be
included. Whereas function is a separate task and need to include header files. Therefore operators are
simple to use compared to functions.
The functions malloc(), calloc() and free() can also be used in C++ for DMA just like in C. But they are having
heavy syntax , so C++ manufactures provided new for malloc() and delete for free(). But these new and
delete are operators not functions like malloc() and free().
‘new’ operator: It allocates user wanted size of memory and gives starting byte address of such memory.
Unfortunately, if enough memory is not available to allocate then returns NULL value.
Syntax: pointer = new data-type; // creates space for single item
pointer = new data-type[5]; // creates space for 5 items (array of 5 items)
Let us see, how above allocated memory is mapped to the pointer ‘p’
If you are creating memory for floating point values, then float* type pointer is required.
For example creating memory for ‘N’ floats. Here ‘N’ is the input value
Creating memory for class objects: we can create class objects dynamically using new operator.
when we create class objects using the new & delete then compiler automatically calls the constructor and
destructors. Let us see with Date class example.
Demo: Comparing two dates whether they are equal or not, creating dynamic memory for objects using
new and delete operators.
#include<stdio.h>
class Date int main()
{ int d, m, y; { Date *p, *q ;
Date() p=new Date(10,4,2020); // creating single object
{ d=m=y=0; q=new Date(10,4,2020); // creating single object
} if ( p->compare(q)==true)
Date( int d, int m, int y) printf(“equal”);
{ this->d=d; this->m=m; this->y=y; else
} printf(“ not equal “);
bool compare( Date *q) }
{ if( d == q->d && m==q->m && y==q->y )
return true;
else return false;
}
};
Demo program on strings, here two programs are explained with static and dynamic allocation to keep
the string data. The following add() function in the String class concatenates two string objects and
returns the result. Initially, we assign two sample strings, 'hello' and 'world' to objects ob1, ob2.
We have used a static array ‘char a[100]’ to store the input string in first program .
#include<stdio.h>
#include<string.h> int main()
class String { String ob1,ob2,ob3;
{ char a[100]; ob1.set("hello");
public: ob2.set("world");
void set( char str[] )
{ strcpy(a , str ); ob3=ob1.add(ob2);
} ob3.show(); // helloworld
String add( char str[])
{ String t; ob3=ob1.add(" hi ");
strcpy(t.a , a); ob3.show(); // hello hi
strcat(t.a , str ); }
return t;
}
String add( String ob2)
{ String t;
strcpy(t.a , a);
strcat(t.a , ob2.a );
return t;
}
void show()
{ printf("\noutput is:%s", a );
}
};
58 C++ DMA | C-Family
This is same as above program with small modification, instead of static array, we have taken dynamic
array to store the string data.
Addition of two matrix using DMA. Here we have taken Dynamic 2D array to store matrix data as well as
the objects created using DMA
#include<stdio.h>
class Matrix int main()
{ int **a ; // pointer 2D array { Matrix *x,*y,*z;
int r , c; x=new Matrix(2,3);
public: y=new Matrix(2,3);
Matrix(){r=c=0;}
printf("enter 1st matrix data\n");
Matrix( int r, int c)
x->scan();
{ int i;
a=new int* [r]; // creating ‘r’ rows
printf("enter 2nd matrix data\n");
for(i=0; i<r; i++)
y->scan();
a[i]=new int[c]; // creating ‘c’ columns
this->r=r; this->c=c;
z=x->add(y);
}
z->show();
void scan() }
{ int i , j;
for(i=0; i<r; i++) following pictures shows how object ‘X’ occupies
{ for(j=0; j<c; j++) memory space in the RAM.
{ printf("enter value of a[%d][%d]:",i,j);
scanf("%d", &a[i][j]); X a r c
} 2000
} 4000 2000
}
void show()
{ int i,j;
for(i=0; i<r; i++)
{ for(j=0; j<c; j++) a[0] a[0][0] a[0][1] a[0][2]
printf("%4d ",a[i][j] ); a[1]
printf("\n"); a[2] a[1][0] a[1][1] a[1][2]
…
}
… a[2][0] a[2][1] a[2][2]
}
Matrix* add( Matrix *y ) … …
{ int i,j;
… …
Matrix *t=new Matrix(r,c);
for(i=0; i<r; i++)
{ for(j=0; j<c; j++)
t->a[i][j]=a[i][j]+y->a[i][j];
}
return t;
}
};
60 C++ DMA | C-Family
61 Constructor & Destructor| C-Family
Constructor is a special member function in the class, where we write all these initialization instructions or
resource allocate instructions required by the object. So the constructor prepares the object ready for use.
While destructor is quite opposite to constructor, where it releases (deletes) such allocated resources before
destroying the object.
Before knowing more about constructors, first we would learn need of constructors with previous
knowledge. First, let us remember the difference between initialization and assignment.
The following example shows how we did in C language.
Initialization Assignment
Assigning values at the time of declaration is Assigning values to each member separately after
said to be initialization. Following code gives declaration of variables is said to be assignment.
an idea how arrays and structures are int a[3];
initialized in C. a[0]=10;
a[1]=20;
int a[3] = { 10, 20, 30 }; a[2]=30
In C++, objects cannot be initialized like in C, because according to object oriented programming (OOP)
principles, all operations on object members—such as reading values, initializing values, printing values, and
calculating values—must be performed inside the class through member functions. No operations should be
performed outside the class.
Thus, we should not assign or initialize values to objects in the main() function or any other non-member
function. This rule applies to both assignments and initializations of class members. The following examples
show some valid and invalid assignments/initializations.
int main()
{ Date ob; // here space creates for day, month, year in ‘ob’ ;
-------
-------
}
We can’t initialize data members like above shown, because space for data members will not be
created inside the class. (Remember, members space creates in the object). Therefore, it shows an
error.
The set() function is used to assign the values to object, whereas constructor is used to initialize the object.
We have already learned more about set() function. Let us move to the constructors.
63 Constructor & Destructor| C-Family
Constructor
Constructor is a special member function with same name as class-name and automatically called when
object is created and used to initialize the object. Constructor does not have return-type including void.
Constructors can be overloaded too. A constructor that takes no arguments is called a default constructor,
while one that takes arguments is called a parameterized constructor. Constructors are like any other
function and can contain any code. This makes the object ready for use.
Like set() function, constructor also validate the data before initialization. Constructor and set() functions
may seem similar at one point (while assigning values to members), but they serve different purposes.
Constructors are used to initialize an object when it is created, while set() functions are used to assign or
update values later part of the program after the creation of object. Let us see syntax of constructors.
class Date
{ int d,m,y;
public: #include<stdio.h>
Date() int main() Date ob1;
{ d=m=y=0; { ob1.Date();
} Date ob1;
Date(int y) Date ob2;
Date ob2(2022);
{ d=m=1; ob2.Date(2022);
this->y=y;
Date ob3(10,5,2022);
} Date ob2;
Date(int d, int m, int y) ob1.show(); ob2.Date(10,5, 2022);
{ this->d=d; ob2.show();
this->m=m; ob3.show();
this->y=y; }
}
Date is 00-00-0000
void show()
Date is 01-01-2022
{ printf("\nDate is %d-%d-%d",d,m,y);
Date is 10-05-2022
}
};
Similarly, the instruction ‘Date ob2(2022)’ is converted into two instruction by the compiler as
Date ob2;
ob2.Date(2022); // calling parameterized constructor 1
In a typical scenario, a class is written by a person 'X', while the main() is written by another person 'Y'.
'X' anticipates all the possible functionalities 'Y' might need later. Therefore, it's better to write all
possible constructors in the class. This is like below Time class.
#include<iostream>
using namespace std;
class Time
{ int h,m,s; int main()
public: {
Time() Time ob1;
{ h=m=s=0;
} Time ob2( 7450 );
Time( int n )
Time ob3(4,20,40);
{ h=n/3600;
m=n%3600/60;
ob1.show();
s=n%3600%60;
ob2.show();
}
ob3.show();
Time (int h, int m, int s) }
{ this->h=h;
this->m=m; output is: 0 0 0
this->s=s; output is: 2 4 10
} output is: 4 20 40
int show()
{ printf("\n output is %d:%d:%d", h, m, s);
}
};
Constructors are called for every object in the program and objects may found anywhere in the program.
let us see following program
If no constructor is written in the class, Observe how the default constructor added by the
then compiler creates a default compiler
constructor with an empty body.
For example Test() { }
class Test
class Test { int a , b;
{ int a , b; public:
public: Test() // this is added by compiler
void show() {
{ ------- }
------- void show()
} { -------
}; }
int main() };
{ Test ob; int main()
------- { Test ob;
} ------
}
This program explains how C++ code converts into C code by the compiler with the help
of this pointer.
int main()
int main() {
{ struct Test ob1;
Test ob1; ob1.Test(); // this line added by the compiler to call
default-constructor
Inserting values in list and printing on the screen, here constructor creates array of user
wanted size.
int main() class List
{ List ob(10); // list size (array-size) { int *arr, size, count;
ob.add(14); public:
ob.add(5); List( int size)
ob.add(11); { arr=new int [ size ];
ob.add(16); this->size=size;
ob.show(); count=0;
} }
output: 14 5 11 16 void add( int x )
{ if( count==size)
{ printf(“error , array full ”);
return;
}
arr[ count++ ] = x;
}
void show()
{ for(int i=0; i<count; i++)
printf(“%d “, arr*i+ ):
}
};
68 Constructor & Destructor| C-Family
Destructor
This is opposite to a constructor. A destructor is automatically called just before an object is going to be
destroyed. Its name is the same as the class name, but prefixed with a tilde (~) symbol. Unlike constructors,
destructors cannot be overloaded, so only one copy is allowed in a class. Destructors are mainly used to
delete dynamically allocated memory, close files, and release other resources.
syntax: ~class-name() // this is destructor
{ ------
------
}
Exercise: Finding sum and product of given input N (let N=5) ( 1+2+3+4+5 , 1*2*3*4*5 )
Following code has some mistakes, correct the mistakes yourself
#include<stdio.h>
class Finder
int main() { int sum=0, product=1, n, i;
{ public:
Finder ob; void initialize(int n)
ob.initialize(5); // convert this call to constructor { this->n=n;
ob.find(); }
ob.print(); void find()
{ for(i=1; i<=n; i++)
} { sum=sum+i;
product=product*i;
}
}
void print()
{ printf("\n %d , %d", sum, product);
}
};
Correct the following code at set() function to delete previous DMA if any, and also write destructor
to release such DMA.
#include<stdio.h>
#include<string.h>
int main() class String
{ String ob("hello"); { char *p;
ob.print(); public:
ob.set("world"); String()
ob.print(); { p=NULL;
}
for(int i=0; i<5; i++) String(char *p)
{ String ob("world"); { this->p=new char[100];
ob.print(); strcpy(this->p,p);
} }
} void set(char *p)
{ this->p=new char[100];
strcpy(this->p,p);
}
void print()
{ printf("\nstring is:%s",p);
}
};
70 Constructor & Destructor| C-Family
71 hiding and abstraction | C-Family
Abstraction
Abstraction refers to the concept of hiding complex details and presenting only the essential information to
the user. It is a way of providing a simplified access interface to the user while hiding the internal working
mechanism of a device or system. For example, a power switchboard in our home is used to control fans,
tvs, lights, motors, etc. The switchboard is a good user-friendly interface for controlling these devices and
also hides their internal working mechanism. The user may or may not know how they work; he simply
controls them through switches.
Let's consider another familiar example that many authors use in books to illustrate this concept more
clearly. The car brake system is completely abstracted from the driver. The brake system can be disk, drum,
or hydraulic. The driver may not be aware of the type of brake system and how it works. They simply press
the brake pedal to stop the car. In this case, the brake pedal serves as a user-friendly interface, visible and
accessible to the driver, while its underlying functionality remains hidden. Let us come to code example.
class1 class2
class Student class Student
{ int idno, marks1, marks2; { int idno, marks1, marks2;
char name[30], address[50]; char name[30], address[50];
int total, average, rank; int total, average, rank;
public: public:
void showAll() { ------- } void showAddress() { … }
--------------- void showMarks() { … }
}; void showRank() { … }
void showAll() { ------- }
---------------
};
Here class1 and class2, both designed to represent students. class1 offers less abstraction, with only one
function, showAll(), which displays all details of a student though user’s requirement is to view only their
rank. class2 provides more abstraction by offering different functions that allow the user to access specific
details, such as their rank. Here showRank() fn displays only rank and hides other details such as address,
marks, total, average. In this way by writing more abstracted functions makes more convenient to user.
The function showRank() also hides the logic to the user how it calculates the rank. This is entry level
example for abstraction and we can create multiple levels of abstractions.
72 hiding and abstraction | C-Family
Abstraction is implemented in two ways in programming: data abstraction and functional abstraction.
We also use abstraction in our daily lives without even knowing it.
Let's look at some models on data abstraction in our everyday experiences.
For example: Device electronic device cell phone Apple iPhone.
The term 'Device' is a higher-level abstraction compared to ' Apple iPhone’.
A cell phone incorporates various sub-devices like GPS, sound, microphone, and camera. These components
exemplify data abstraction, while the buttons on the device represent the functional abstraction. Let us
come to code examples.
class Date
{ private:
int day, month, year; int main()
public: { Date ob;
void setDate(…) { … } ob.setDate(10, 4, 2020 );
void setYear(…) { … } ob.incrementDate();
void incrementDate() {…} ob.showDate();
void decrementDate() {…} }
void showDate() {…}
void showYear() {…}
};
Let this class developed by a person ‘X’ Let this main() fn developed by a person ‘Y’
The functions such as setDate(), setYear(), setMonth(), showDate(), showYear() comes under data
abstraction. These are used to read/write values of data members from outside of class.
The functions such as incrementDate(), decrementDate(), compareDates() comes under functional
abstraction.
These are used to compute the data for finding certain result of user requirements. From the first example,
the showRank() fn shows only rank and hides other details such as address, marks, total (data abstraction).
the showRank() fn also hides the logic how it calculates the rank from marks. (functional abstraction).
The showRank() fn serves as data abstraction as well as functional abstraction.
In this way, writing suitable controlled interface functions to the class makes good abstraction.
In programming, the abstraction is done through private, public, functions, classes, and namespace.
Using these tools we can make several different levels of abstractions.
Finally one question may arise, who do the abstraction and who enjoys it.
In development environment, the class is written by a person, say X, and main() fn is written by person Y.
The person ‘X’ abstracts the data & functionality of the class to person Y. (as shown above example)
The person ‘X’ keeps some unwanted members in private section and wanted members in public section.
From the main() function, the person ‘Y’ simply access/manipulate the class data through public interface
functions like setDate(), setYear(), incrementDate(), decrementDate(), showDate(), showYear(), etc.
Here person ‘Y’ is the beneficiary.
While we have discussed the benefits of abstraction for person Y, it also significantly advantages to person X.
The person ‘Y’ access the class data members through public interface functions such as ob.setDate(),
ob.showDate(), ob.showYear(). He would not access directly like ob.day, ob.month, ob.year at main() fn.
So, the person Y need not to know the names and types of data members used by person X in the class.
73 hiding and abstraction | C-Family
If X changes the class variable names or types or count then no need to modify the code in the main()
function ( it does not affects the code in main() fn ). Sometimes, X can add extra functionality to the class
without disturbing other part of code. So X is also free from other part of code. ( X also beneficiary) .
In the development industry, many people are involved in coding, not just two persons like above said X&Y.
Several classes can be written by different developers and shared with others. Some classes might be part of
an API library, while others would be third-party libraries.
Previously, I mentioned that we can have multiple levels of abstraction. For example, function1 might call
function2, which in turn calls function3. This creates a hierarchical structure of functional abstraction.
The concept of inheritance itself represents hierarchical abstraction, where classes inherit data and
functions from other classes, creating multiple levels. The examples we've seen so far have demonstrated
limited abstraction.
Understanding high level abstractions can be challenging for beginners, but abstract classes with virtual
functions provide some clarity. For instance, Vehicle *p = new Vehicle (new Car()); (we'll explore this further
in later chapters). The primary goal of abstraction is to reduce dependencies and complexities, making
systems easier to use and maintain.
74 hiding and abstraction | C-Family
75 oop concepts | C-Family
C is a structured and function-oriented language. Structured means the language provides good control
statements along with building blocks of code defined by braces { } . And also breaks down a big program
into several functions. Therefore, it is said to be a structured programming language as well as a function-
oriented language.
Before the C language, older languages like BASIC, Fortran, Algol, and Pascal did not provide proper control
statements. These were considered unstructured languages. In contrast, C offers robust control statements
with building blocks using braces {} , making it a well-structured language.
In C, large programs are divided into several modules at the design level, and these modules are
implemented as functions during coding. Ultimately, the entire program becomes a collection of functions.
Therefore, C is often referred to as a function or procedure-oriented language.
The main issue with function-oriented languages is that all functions are defined globally. This means that
any function can call any other function from anywhere in the program. As the number of functions
increases, the complexity and potential for confusion also increase.
Additionally, in C, data and functions are defined as separate entities. Data is often organized using
structures, but when there are many structures and many functions, it becomes difficult to determine which
function is processing which data. This can lead to confusion and increased complexity for the programmer.
Structured programming is suitable for smaller programs, typically those with fewer than 50,000 lines of
code. However, it becomes inadequate for larger applications.
Object oriented programming is a way of writing programs by following some principles and approaches.
We have mainly three standard principles: encapsulation, polymorphism and inheritance. By following these
principles one can solve complex programs easily. No doubt these approaches were designed and tested
thousands of times on different projects before introducing to the world.
Structured languages mainly focus on functionality, whereas object-oriented languages focus on data
alongside functionality. In structured languages, programs appear to be collections of functions, whereas in
object-oriented programs appear to be data with functions. In this programming, a large program is divided
into several modules, each designed and developed in terms of both data and functionality, following three
key principles. Each module is called an object, and instructions are written in terms of objects, which led to
the term 'object-based programming’, later evolving into 'object-oriented programming’. Following picture
explains how function and oop programs seem
76 oop concepts | C-Family
object2 object3
Function4 Function5 Function6 Data + Functions Data + Fnctions
If there are no ideal structural approaches to force the programmer to write the code in systematic way then
everybody writes one’s own style and makes the program complex and un-readable to others. For example,
if there are no predefined traffic rules in city roads, everyone travels as per one’s convenience and makes
traffic disorders and cause inconvenience to others; so the traffic structures such as signals, dividers, zebra
lines and indicators force the traveller to follow rules in order not to cause confusion.
In structured languages, there were no good ideal approaches to write big programs in systematic way.
Here everyone writes one’s style and causes complexity to others. In object oriented languages everyone
writes same style of coding by following these principles and approaches. So we get uniform style of coding
thereby easy to understand & update. When we follow uniform style coding, others can follow easily.
The main three approaches are: encapsulation, polymorphism, inheritance.
Encapsulation
Encapsulation refers to the concept of packing data items and its manipulation functions together as single
unit. The exact meaning of encapsulation in OOP includes: packing, hiding, abstraction, and modularity.
In the C language, a structure is a tool that groups several data items together as a single unit.
Similarly, C++ provides a tool called a ‘class’ to support the concept of encapsulation.
A class is a tool that combines data and its manipulation functions into a single unit. It encapsulates or wraps
the data and functions together, promoting data hiding and abstraction. These data hiding and abstraction
can be taken as by-product of class. We have already discussed classes and their syntax. Additionally,
namespaces contribute to encapsulation by resolving name collisions between classes, variables, and
functions.
Polymorphism
The term 'polymorphism' is derived from Greek, where 'poly' means many and 'morph' means form.
‘Poly’ refers to many similar related things or actions, while 'morph' refers to transforming them into a single
thing or action.
In C++, polymorphism refers to having many forms with the same interface. Let’s look at a real-world
example. Different cars use different braking systems like drum, disk, hydraulic, air, ABS, dual, etc. However,
all cars have the same brake pedal interface. In other words, pressing the brake pedal is the same in all cars,
and drivers may not even be aware of which braking system is in use. Similarly, in C++, polymorphism allows
objects, functions, or operators to behave differently depending on the context in which they are used.
Polymorphism is classified as shown below.
77 oop concepts | C-Family
Polymorphism
In the C language, we cannot assign the same name to more than one function; each function carries unique
name. However, in C++, the same name can be given to two or more functions, provided their parameters
are different. This feature falls under the concept of compile-time polymorphism in OOP.
This feature makes it more convenient to remember function names related to the same action, and it also
makes the functions easier to understand and use. Defining multiple functions with the same name but
different parameters is known as function overloading, which is a concept of compile-time polymorphism in
C++. We have already discussed this in previous topics.
Operator overloading is a shorthand term for operator function overloading, and it also falls under static
binding or early binding. In this case, instead of using a function name, we use the operator symbol when
writing the function body.
Compile-time polymorphism is also called static binding or early binding because the function-call
statements are linked or bound to the function body during compilation. In contrast, in runtime binding,
function-call statements are linked or bound to the function body during program execution, based on input
values. This concept is also known as late binding, dynamic binding, or runtime binding. In this case, the
functions are called virtual functions. Nowadays, this virtual functions concept is also function-over-riding
(this topic will be covered in the next chapters).
------------------------------------------------------------------------------------------------------------------------------------------------
Inheritance
Inheritance is the concept of sharing one class's properties with another class, similar to how a child inherits
properties from a parent, such as a car, bike, home, etc.
It is a fundamental concept in object-oriented programming (OOP) that allows a class (derived class) to
inherit data properties and behaviours (methods) from another class (base class). This promotes code
reusability, flexibility and establishes a hierarchical relationship between classes. Let us take college
administration example
class Person
{ char name[30];
char address[50];
int age;
---------
};
As per C++ author version, these two declarations are said to be declaration & definition. Some people use
these terms interchangeably, which creates confusion for others. If you are a beginner to programming,
the definition and declaration of the term might be highly confusing. For avoiding confusion, modern
programmers are using these two words as proto-type & declaration.
---------------------------------------------------------------------------------------------------------------------------------------------
Let us see some practical examples, how static variables are shared among objects.
class Circle
{ float radius, area;
static float pie; // only one copy of ‘pie’ creates for all objects of circle class (like global variable)
--------------
--------------
ob1 ob2
}; 5 78.5 6 113.04
float Circle::pie=3.14F; radius area Radius area
void main()
3.14
{ Circle ob1(5) , ob2(6) ;
pie
--------------
--------------
};
Different circles have different sizes of radius and area but all circles ‘pie’ value is same, so it is better to
create only one copy and shared to all objects using static as shown above example.
---------------------------------------------------------------------------------------------------------------------------------------------
more about static
In fact, static variables are used in two ways in the program, first style used to share them to all objects of
that class, and second style used as global variables or constant, but most of the time we use them in first
style only.
In case of first style use, we declare them in private section, so that, they can be accessed only in member
functions of that class. As we have only one copy of static data, all member functions share same data.
In this way, all objects share same data of static through its member functions.
In case of second style use, we declare them in public section, so that, we can access them as global variable
or global constant. Here the scope resolution operator(::) is required to access from outside of class. for
example Math::pie (π), Color::green, Currency::rupees, etc.
Now you may get one doubt, what is the advantage of using static variable over global variable when a
global variable concept is available in C++. Static variable gives more clarity than global variable and also
avoids misusing. For example, the expression “Math::pie” tells that, we are accessing ‘pie’ value from Math
class. So these are somewhat clarity with security.
80 static data member | C-Family
Global and static variables behavior is same, that is, in compiler perspective there is no technical difference
between them except declaration place and accessing style to the user.
When we come to accessing of static variable, if we are inside the class, that is, we are inside of member
functions, the static variables can be accessed just as instance variables (scope operator is not required)
but when we are outside of class, we have to access with class-name or object, but class-name is
recommended. For example, Math::pie, Currency::rupees, etc.
Accessing static with object is not recommended, because other programmers may get confused whether it
is static or non-static member. Let us see some examples one by one,
class Test
{ public:
static int X;
void show()
{ printf(" %d ", X ); // inside member function, the static can be accessed just like instance variable.
}
};
int Test::X=10; // here space creates for ‘X’ with initial value 10.
void main()
{ printf(“ output is %d “ , Test::X ); // here class-name is required to access static from outside of class.
Test ob;
printf(“ output is %d “ , ob.X ); // remember, this style of accessing with object is not recommended
ob.show(); // output is: 10
}
Note: Remember, the expressions Test::X and ob.X access the same memory for X (since X is available as a
single copy throughout the program). Therefore, all printf() statements in this program show the same
output.
-----------------------------------------------------------------------------------------------------------------------------------------------
Example: this example explains how static variable works as global.
class Test
{ public:
static int X , Y; // this is proto-type of X,Y.
void increment()
{ X++; or Test::X++; // both are valid syntax, but “Test::X++” is not recommended inside class
Y++; or Test::Y++;
}
};
int Test::X=10; // this is declaration of static variable X, here space for X will be created with initial value is 10.
int Test::Y; // this is declaration of static variable Y, here space for Y will be created with default initial value is 0.
void main()
{ printf(“%d %d”, Test::X , Test::Y ); // 10 0
Test ob;
ob.increment();
printf(“%d %d”, Test::X , Test::Y ); // 11 1
Test::X++; Test::Y++;
printf(“%d %d”, ob.X , ob.Y ); // 12 2
printf(“%d %d”, Test::X , Test::Y ); // 12 2
printf(“%d %d”, X , Y ); // error, undefined symbols X,Y. ( should be accessed with class-name or object)
}
---------------------------------------------------------------------------------------------------------------------------------------------
81 static data member | C-Family
ob2.add();
ob2.show(); // 10 20
ob3.add();
ob3.show(); // 10 30
}
remember: In this program, ‘x’ has 3 copies in the form of ob1, ob2, and ob3 but ‘y’ has only one copy.
------------------------------------------------------------------------------------------------------------------------------------------
83 static data member | C-Family
Initialization of static members in constructor
by mistake many people initialize the static members inside the constructor, it leads to improper result in
the program. Let us see, following example.
class Test
{ public:
static int x;
Test() { x=0; }
void add()
{ x=x+100;
}
};
int Test::x;
void main()
{ Test ob1;
ob1.add();
ob1.add();
Test ob2; // here constructor will be called and makes the x to zero
printf(“%d “, ob1.x ); // output is : 0 ( not 200 )
}
we don’t initialize the static member inside the constructor, otherwise re-initializes every time when new
object is created. We expect the output as 200, but it shows 0
6) As we know, static should be declared two times in the program, this seems to be complex and
confusion syntax. This is one of the main drawback in c++ syntax.
85 static data member | C-Family
Namespaces
There are two students with the same name in a classroom. To distinguish the two students, we need to call
them by their names with surnames. A situation like this can occur in C++ as well. For example, if we write a
function with name sqrt(), then it conflicts with the already existing library function sqrt() provided in
math.h. In this case, the compiler cannot differentiate between the two function names. Hence, it will yield
an error. To avoid this confusion, namespaces are used.
Namespace was introduced in second version of C++. They faced naming problem over 3rd party libraries
produced by different companies, conflicts happened over names of global variables, functions and classes.
For solving this they had to develop namespace concept.
syntax of namespace
namespace namespace-name // here “namespace” is a keyword
{ variables-list;
functions-list;
classes-list;
nested-namespace-list; // namespace can be nested
}
Points to note
We can have any number of namespaces in a program, and namespaces can also be nested.
Generally, namespaces are declared in the global scope; however, they can also be declared in a function's
local scope, though only some compilers support this. Namespaces have many features, but they are not
covered in this book.
The C++ compiler itself provides some libraries with namespace ‘std’ (also called the Standard Template
Library). This namespace contained so many program elements. for example std::cin, std::cout, std::string,
std::vector, std::list, std::array, std::queue, etc.
we will see more about this ‘std’ namespace in the next chapters.
90 namespaces | C-Family
91 console i/o | C-Family
cout<<”hello:” // printf(“hello” );
cout<<”hello\nworld”; // printf(“hello\nworld”);
We have two API library classes called istream and ostream defined in the iostream.h file.
These are stream classes used for input/output operations in C++.
The ‘istream’ class has full of input functions for reading values from keyboard, while the ‘ostream’ class
with full of output functions for printing values on the screen.
Both classes consist of all overloaded functions for reading and writing all built-in types data, including
int, float, char, char*, void*, etc.
For each data type, there is a suitable overload function provided in these classes.
The cin is an object of istream class, and the cout is an object of ostream class.
These two objects defined globally in iostream.h file under the std namespace.
We use stdio.h header file to use printf() and scanf()statements, similarly, iostream.h header file is used
for cin and cout.
In modern compilers the include statement should be in #include<iostream> (here .h not required)
These are similar to scanf() and printf() functions in C, but the main difference is that cin and cout do not
use formatted strings like %d, %f, %s, etc.
As format strings are not required by cin and cout, these are particularly useful when working with
template classes, where the types of values to be printed are unknown.
We can use both c & c++ io statements at a time without any conflict. We can mix C & C++ io statements
in a program.
The cin object is linked with the extractor operator (>>), and the cout object is linked with the inserter
operator (<<). The operator inserter(<<) inserts values into the output stream(monitor). That is, the
inserted value reflects on the screen. The operator extractor(>>) extracts values from the input
stream(keyboard) and assigns into given variables.
-----------------------------------------------------------------------------------------------------------------------------------------------
93 console i/o | C-Family
#include<iostream> Output
#include<iomanip> 1 2 3
using namespace std; * * * * * 1 2 3
A A A A A 1 2 3
int main()
@ @ @ @ @ 1 2 3
{ cout<<setw(5)<<123<<endl;
A B C
cout<<setfill('*')<<setw(7)<<123<<endl;
cout<<setfill('A')<<setw(7)<<123<<endl;
cout<<setfill('@')<<setw(7)<<123<<endl; 1 2 3 . 4 5
cout<<hex<<10<<11<<12<<endl; // hexa decimal . 2 3 e + 0 0 2
1
cout<<fixed<<setprecision(2)<<123.4556f<<endl;
cout<<scientific<<setprecision(2)<<123.455f<<endl;
}
Operator overloading
Let us come to a simple addition on class objects, previously, we have added two objects like ob1.add(ob2)
and compared like ob1.compare(ob2). We have written and called the member functions in that way.
Generally, we add two integers like 10+20. In the same style, if we add two class objects using the ‘+’
operator, such as ob1+ob2, it would be a great choice for the programmer to handle class objects as easily
as any built-in types, such as int, float, etc. The operator overloading concept allows us to handle class
objects in this way.
Let us take two types of addition: 10+20 and 10.45+59.34. The first one is integer addition, and the second
one is float addition. In both cases, the same ‘+’ operator is used. Even though both values are added using
the same ‘+’ operator, the compiler generates different machine code for different data types, because the
machine code for integer addition is not the same as for float addition. In this way allowing same ‘+’
operator for different types of data is said to be operator overloading, and this ‘+’ operator is overloaded at
the compiler level to support all built-in types of data. Of course, we have been using the ‘+’ operator
without this knowledge from the first day. The compiler manufacturers overloaded all operators on all
built-in type data. This is also called functional abstraction at the compiler level.
In C++, this concept is expanded to allow programmers to create custom type additions on objects. Not only
can we perform addition, but we can also do all arithmetic, relational, and logical operations. Previously, we
have added two objects like ob1.add(ob2) and compared like ob1.compare(ob2). Now, using the operator
overloading concept, we can add as ob1+ob2, and we can compare as ob1==ob2, etc. This is 100% similar to
operations on integer like 10+20 and 10==20. In this way, using the operator overloading concept, we can
handle our class objects just like any built-in types. The main objective of operator overloading is to create
our own class-based user-defined data types that can be used similar to built-in types. This comes under
polymorphism concept, where one interface can take many forms.
Operator overloading is a good choice for frequently used objects, such as Time, Date, DateTime objects.
However, for normal use objects, the call expression ob1.add(ob2) is sufficient instead of ob1+ob2.
For frequently used objects, like those in API class libraries, operator overloading would be a better choice.
The term ‘operator overloading’ is a short name for operator function overloading. This is very similar to the
concept of function overloading. Actually, the operator overloading is nothing but a function with a special
syntax. While writing the function body, we use an operator symbol in place of function name. Here, the
operator symbol acts as the function name. Syntax for operator-function is,
return-type operator <symbol> ( parameters list ) // here symbol can be any + , - , * , < , > , etc
{ ---------
---------
return value;
}
The compiler converts the expression ob1+ob2 into a function call statement as ob1.operator+(ob2).
Here the word ‘operator’ is a keyword added by the compiler as a function-name with its symbol ‘+’.
Thus the “operator+” works as a function-name in the program.
Let us have one example, adding two time objects using symbol ‘+’ as
int main()
{ Time ob1(4, 5, 20), ob2(3, 15, 50), ob3;
ob3=ob1+ob2; ob3 = ob1.operator+(ob2); , remember this is a function-call statement
ob3.show();
}
class Time
{ ------
Time operator+ ( Time ob2 ) // this is a function-body. Observe that function name is ‘operator+’
{ Time t;
---------
return t;
}
----------
};
---------------------------------------------------------------------------------------------------------------------------------------------
Addition of two players score in a game using “operator+” function.
int main()
{ Player ob1(10) , ob2(20), ob3; // ob1, ob2 holds two player’s score. Initially taken as 10, 20
ob3=ob1+ob2; ob3=ob1.operator+(ob2) , remember this is a function-call
ob3.show();
}
class Player
{ private: int score;
public: Player() { score=0; }
Player( int s ) { score = s; } ob3 = ob1 + ob2;
Let us see how following expressions are converts into function-call statements.
ob1 + ob2 ob1 . operator + ( ob2 )
ob1 + 100 ob1 . operator + ( 100 )
100 + ob1 operator + (100 , ob1 )
ob1 * 100 ob1 . operator * ( 100 )
ob1 / 100 ob1 . operator / ( 100 )
ob1 < 100 ob1 . operator < ( 100 )
100 < ob1 operator < ( 100 , ob1 )
++ob ob.operator++();
----------------------------------------------------------------------------------------------------------------------------------------------
Finding addition of two times which is employee worked in 2 shifts, and also adding seconds to time.
ob3=ob1+ob2; this instruction adds two time objects ob1 & ob2 into ob3
ob3=ob1+7200; this instruction adds ob1 & 7200 seconds into ob3
#include<stdio.h>
class Time
{ int h,m,s;
public:
Time() { h=m=s=0; }
Time(int h, int m, int s) { this->h=h; this->m=m; this->s=s; }
Time operator+( Time ob2)
{ Time t; int x;
x= (h+ob2.h)*3600 + (m+ob2.m)*60 + (s+ob2.s);
t.h = x/3600;
t.m = (x%3600)/60;
t.s = (x%3600)%60;
return t;
}
Time operator+( int x )
{ Time t;
x=x+h*3600 + m*60 + s;
t.h = x/3600;
t.m = (x%3600)/60;
t.s = (x%3600)%60;
return t;
}
void show()
{ printf("\n output is %d : %d : %d", h,m,s);
}
};
int main()
{ Time ob1(5,20,30) , ob2(3,40,50) , ob3;
ob3=ob1+ob2; // ob3=ob1.operator+(ob2);
ob3.show();
ob3=ob1+7200; // ob3=ob1.operator+(7200); adding 7200 is seconds
ob3.show();
}
98 operator overloading | C-Family
Here before returning a+b value to main() function, the compiler stores the a+b value into a temporary
variable and then returned. Actually, this temporary variable is a nameless variable created & destroyed by
the compiler. For a while, let us say its name is 'temp'. The data type of ‘temp’ is depends upon a+b result
type. The above function-body can be imagined with ‘temp’ as:
int add( int a, int b )
{ int temp;
temp=a+b;
return temp;
}
In this way compiler creates and destroys temporary space when the function has return-value.
temp
temp=ob1+ob2;
temp=temp+ob3; temp+ob3
temp=temp+ob4;
total=temp;
temp+ob4
The 'temp' variable is nothing but a variable that holds the return value of the function, like in the example
said above. The 'temp' is used to hold the return value and also to add with the next object
int main()
{ Complex ob1(10,20), ob2(5,7), ob3;
ob3=ob1+ob2;
ob3.show();
}
Complete the following Date class, which handles operations such as adding days, subtracting days,
comparing days, and printing. The main() function is provided along with sample data to test the program.
101 operator overloading | C-Family
class Date
{ private: int d, m, y;
public: Date() {…}
Date ( int d, int m, int y) { … }
Date operator+( int n) { … } // increment date by n-days
Date operator-( int n) { … } // decrement date by n-days
bool operator==( Date); // check two dates are equal or not
bool operator<( int days) { … } // compare whether ob1<ob2
bool operator>( int days) { … } // compare whether ob1>ob2
bool operator ! () {…} // checks whether date is valid or not
void show() { … }
};
int main()
{ Date ob1(10,5,2020), ob2(12,4,2020), ob3;
ob3=ob1+365;
ob3.show();
ob3=ob1-365;
ob3.show();
if( ob1<ob2) cout<<” Date1 < Date2 ”;
else cout<<” Date1 < Date2 ”;
if( ob1==ob2) cout<<” two dates are equal ”;
else cout<<” two dates are not equal ”;
if( !ob ) cout<<” in valid date ”;
else cout<<” valid date ”;
}
------------------------------------------------------------------------------------------------------------------------------------------------
Complete the following Time class, which handles operations between two time objects such as addition,
subtraction, comparison, and printing. The main() fn is provided along with sample data to test the program.
class Time
{ private: int h, m, s;
public: Time() {… }
Time( int d, int m, int y) { … }
Time operator+( int n) { … } // increment Time by n seconds
Time operator-( int n) { … } // decrement Time by n seconds
bool operator==(Time) { … } // check two Times are equal or not
bool operator<( Date ob2) { … } // compare whether ob1<ob2
bool operator>( Date ob2 ) { … } // compare whether ob1<=ob2
void show() { … }
};
int main()
{ Time ob1(4,5,40), ob2(2,4,50), ob3;
ob3=ob1+7200; ob3.show();
ob3=ob1-7200; ob3.show();
if( ob1<ob2) cout<<”time1<time2”;
else if( ob1>ob2) cout<< ”time1>”time2”;
else if( ob1==ob2) cout<<”two times are equal”;
else cout<<”two times are not equal”;
}
------------------------------------------------------------------------------------------------------------------------------------------------
102 operator overloading | C-Family
The instruction ob++ is converted into a function call as ob.operator++(0). Here, the argument zero is added
by the compiler as a dummy argument to differentiate between pre- and post-increment. Thus, the
expression is converted into a function call.
++ob ob.operator++()
ob++ ob.operator++(0)
Let us consider a Player class where we increment the player's score by 1. This example demonstrates
pre-increment and post-increment.
class Player
{ int score;
public:
Player() { score=0; }
Player( int s) { score=s; }
void operator++() // this function calls for pre-increment
{ score=score+1; or score++;
}
void operator++( int dummy ) // this function calls for post-increment. Here dummy does nothing.
{ score=score+1; or score++;
}
void show()
{ cout<<”player score is : “<< score;
// printf(“player score is : %d”, score );
}
};
int main()
{ Player ob(10);
++ob; // ob.operator++();
ob.show();
ob++; // ob.operator++(0);
ob.show();
}
The function operator++() increments the player's score by 1 point. This function currently returns nothing.
However, sometimes this function needs to return the incremented object so that it can be assigned to
another object. For example: ob2=++ob1; here, the incremented value of ob1 is assigned to ob2. In this
case, the function should be written as
ob.operator + (100);
ob+100
operator + (ob,100);
The compiler converts based on the function body found in the program, whether it is a member or non-
member function. If the function body is written inside the class body, it converts using the first style. If the
function body is written outside the class body, it converts using the second style. It is fairly depends on you.
Actually, the first style of writing functions as member functions inside the class makes the code more
flexible and simpler(compiler always looks for this style only) . The second style is used when left hand side
operand is not class object like 100+ob, we will see this in next topic
Operator function inside class body Operator function outside class body
ob + 100 ob + 100
class Player
class Player
{ public: int score;
{ public: int score;
Player() { score=0; }
Player()
Player operator+(int n)
{ score=0;
{ Player t;
}
t.score = score+n;
void show()
return t;
{ cout<<score;
}
}
void show()
};
{ cout<<score;
} Player operator + (Player ob , int n)
}; { Player t;
int main() t.score = ob.score+n;
{ Player ob; return t;
ob=ob+100; }
ob.show(); int main()
} { Player ob;
ob=ob+100;
ob.show();
}
104 operator overloading | C-Family
In the above program, the data member ‘score’ is declared as public to make the code easier to understand.
Generally, we put data members in private section for security. However, if we do that, a non-member
function defined in the second style cannot access private data. To solve this problem, we declare it as a
friend function (revise the concept of friend functions). The following is an updated version with a friend
function.
class Player
{ private:
int score;
public:
Player() { score=0; }
void show()
{ cout<<score;
}
friend Player operator + ( Player, int ); // now this function is friend to class, can access private data.
};
int main()
{ Player ob;
ob=ob+100;
b.show();
}
----------------------------------------------------------------------------------------------------------------------------------------
105 operator overloading | C-Family
ob + 10 1 0 + ob;
Following example explains operator+() function with & without left-hand-side operand by class-object.
Example on Player class objects, where adding score to object like ob+5 and 5+ob.
int main()
{ Player ob1(10) , ob2 ;
ob2=ob1+5; // ob2 = ob1.operator+(5);
ob2.show();
ob2=5+ob1; // ob2 = operator+(5, ob1);
ob2.show();
}
class Player
{ public: int score;
Player() { score=0; }
Player( int score ) { this->score=score; }
Player operator+( int s )
{ Player temp;
temp.score = score + s;
return temp;
}
void show()
{ cout<<”\n score is :”<<score;
}
};
Player operator+( int s , Player ob )
{ Player temp;
temp.score = ob.score + s;
return temp;
}
As per oop concept, everything which belongs to class object should be written inside class such data-
members and member-functions, but C++ compiler manufacturers broke this rule and asked us to write this
function outside class. C++ compiler itself did not follow oop rules in some cases such as static-data-
members, C global functions, namespaces, etc. Thus C++ is not pure object oriented language. However,
many people in the world like C++ as it introduced many new concepts in oop programming.
106 operator overloading | C-Family
In the above program, the data member 'score' is kept in the public section to allow access from outside the
class in a non-member function. However, doing so is not considered good programming practice. It is better
to place it in the private section and access it through a friend function. (See friend function concept)
Let us see modified code above class.
class Player
{ private: int score;
public: -------
-------
friend Player operator( int n , Player );
};
Player operator+( int s , Player ob ) // making this function as friend to above class.
{ Player temp;
temp.score = ob.score + s;
return temp;
}
--------------------------------------------------------------------------------------------------------------------------------------------
Following example explains “operator+()” function with & without left-hand-side operand by class-object.
Explained with Time class object, here 7200 seconds(2hours) are adding to the given Time object.
int main()
{ Time ob1(2, 10, 20) , ob2;
In the last expression, k = ob, we expect it to be an assignment operator overloading (=) and interpret it as a
function call statement like operator=(k, ob). Particularly for this type of expression, the compiler does not
take as we expected. In this special case, the compiler treats it as a type conversion operator, which
requires us to overload it as shown below
k = ob we understand it as k = (int)ob;
therefore, the expression (int)ob converts into a function call as ob.operator int()
ob.operator int()
operator int() // this function does not have return-type, here ‘int’ itself works as return-type.
{ ----
----
}
let us see how following type-cast expressions are converted into a function-call statements as
(int) ob ob.operator int()
(float) ob ob.operator float()
(char*) ob ob.operator char*()
----------------------------------------------------------------------------------------------------------------------------------------------
Following class ‘Test’ gives an idea how to return an integer value from an object using
type-cast operator.
class Test
{ private: int a;
public: Test() { a=100; }
operator int() // does not have return-type. Here ‘int’ itself works as return-type.
{ return a;
}
};
int main()
{ Test ob; int k;
k = ob; // k = ob.operator int();
cout<<"\noutput is:" << k ;
return 0;
}
The expression k = ob; in the main() function can also be written as k = (int)ob;
but the k=ob is simple and enough, because, compiler automatically translates this into k=(int)ob.
Based on the function-body of operator-cast, the compiler automatically translates in this way.
----------------------------------------------------------------------------------------------------------------------------------------------
108 operator overloading | C-Family
Following class ‘Test’ gives an idea how to return a string value from an object using
type-cast operator.
class Test
{ private:
char *a;
Test() { a="hello"; }
operator char*() // this function does not have return-type.
{ return a; // Remember, return type of this function is same as “char*”
}
};
int main()
{ Test ob; char *p;
p=ob; // ob.operator char*();
cout<< ”output is :” << p ;
return 0;
}
---------------------------------------------------------------------------------------------------------------------------------------------
Complete the following code of Date class. Here main() function body provided with some function calls,
based on this calls, implement all functions as needed in the program.
class Date
{ -------
-------
};
int main()
{ Date ob; int n = 12032024; // 12-03-2024
ob = n;
ob.show(); // Date is: 12-03-2024
int n=ob;
cout<<”\n date in integer format is:”<<n; // date in integer format is: 12032024
}
---------------------------------------------------------------------------------------------------------------------------------------------
Complete the following code of Time class. Here main() function body provided with variety of function
calls, based on this calls, implement all functions as needed in the class.
int main()
{ Time ob1(2, 10,20), ob2, ob3;
ob1 = 7290; // ob1 = 2hr, 1min, 30sec
ob2 = 9870; // ob2 = 3hr, 1min, 10sec;
ob3 = ob1 + ob2;
ob3.show();
ob3=3600+ob1;
ob3.show();
int a = ob1; // convert time into seconds and return it.
cout<<” time in second is:”<<a; // 7290
}
109 operator overloading | C-Family
class Time
{ private: int h, m, s;
public: --------
--------
};
--------------------------------------------------------------------------------------------------------------------------------------------
Complete the following class ‘String’ using static & dynamic arrays. Here main() function provided with
variety of string function calls, based on this code, implement all string functions as needed.
int main()
{ String ob1(“hello”), ob2(“world”), ob3;
ob3 = ob1 + ob2;
ob3.show();
ob1 = ”AAA”;
ob2 = ”BBB”;
ob3 = ob1 + ob2;
ob3.show();
char *p;
p = ob1;
cout<<”output is :”<<p; // AAA
}
#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
class Date
{ private: int d,m,y;
public:
Date( int d, int m, int y )
{ this->d=d; this->m=m; this->y=y;
}
int operator() ( int k )
{ if(k==1) return d;
else if(k==2) return m;
else if(k==3) return y;
else return d*1000000+m*10000+y;
}
};
int main()
{ Date ob(12, 5, 2024);
cout<<"\n day in date is:"<<ob(1);
cout<<"\n month in date is:"<<ob(2);
cout<<"\n year in date is:"<<ob(3);
cout<<"\n date in number is:"<<ob(0);
return 0;
}
----------------------------------------------------------------------------------------------------------------------------------------------
111 operator overloading | C-Family
Following program explains Array-List class, it assigns values to object and retrieves the values based on
index. Here two operators are over-loaded assignment operator(=) and parenthesis operator ().
#include<iostream>
using namespace std;
class ArrayList
{ private :
int *a, count, size;
public :
ArrayList ( int size )
{ this->size=size;
count=0;
a=new int[size];
}
int operator() ( int i )
{ if(i>=count)
{ cout<<"\n invalid index";
return -1;
}
return a[i];
}
void show()
{ cout<<"\n output is:";
for(int i=0; i<count; i++)
cout<<a[i]<<" ";
}
void operator=( int v )
{ if( count >= size )
{ cout<<"\n array full , can't be inserted";
return;
}
a[count++]=v;
}
};
int main()
{ ArrayList ob(10);
ob=10; // ob.operator=(10); adds at end of list
ob=20;
ob=30;
ob.show();
int k=ob(1); // k=ob.operator() (1)
cout<<"\nvalue at a[1] is:"<<k;
}
-----------------------------------------------------------------------------------------------------------------------------------------------
112 operator overloading | C-Family
113 overloading assignment & copy constructor| C-Family
ob1 ob2
P
P
2000 “hello” 2000
2000
If the string ‘hello’ is changed through ‘ob1’, it also affects ‘ob2’ because, after the assignment ob2=ob1,
both ob1.p and ob2.p pointers are pointing to the same memory.
From the compiler's perspective, when ob2 = ob1 is executed, the compiler copies only member to member
within the objects but not the outside object's memory (the compiler does not care about outside pointer
pointing memory). Therefore, it only copies the address 2000 of ob1.p to ob2.p. As a result, both pointers
point to the same memory (the same string, “hello”). If the string is changed through ob1.p, it also affects
ob2.p. The following example explains how one object affects the other when pointing to the same memory.
#include<stdio.h>
#include<string.h>
class String
{ private: char *p;
public: String()
{ p=NULL;
}
String( char *p)
{ p=new char[100] ;
strcpy( this->p , p );
}
void change( char *p )
{ strcpy( this->p , p );
}
void show()
{ printf("\n output is %s" , p );
}
};
114 overloading assignment & copy constructor| C-Family
int main()
{ String ob1(“hello”) , ob2;
ob2=ob1; // address is copied to ob2, not ‘hello’
ob1.change(“world”); // if ob1 is changed then it also affects to ob2.
ob1.show(); world
ob2.show(); we expecting “hello” but shows “world” this is wrong output
}
Like above said, when ob2=ob1 is executed then compiler copies ob1.p to ob2.p ( but not string “hello” )
Therefore, the function call ob1.change(“world”), changes the string “hello” to “world”, affecting both ob1
& ob2. The solution is to overload the assignment operator(=) by creating a separate memory for ob2.
The function is as follows
ob1 ob2
P
P 3000
2000 “hello” “hello”
2000 3000
However, this function does not work for multiple assignments, for example, ob3=ob2=ob1; because the
function simply assigns ob1 to ob2 and returning nothing, here the return type is void. So the above function
should be re-written as
String operator=( String ob1)
{ if(p==NULL)
p=new char[100];
strcpy( p , ob1.p );
return ob1; // return of this ob1 is assigned to ob3
}
---------------------------------------------------------------------------------------------------------------------------------------------
115 overloading assignment & copy constructor| C-Family
Copy constructor
String ob1(“hello”);
String ob2(ob1); // this instruction can also be written as: “String ob2=ob1”;
String ob1(“hello”); As we know, compiler cannot initialize “hello” to ob1. It does not know how to put
“hello” to ob1. We need to write a constructor to copy “hello” to ob1. This is what we did previously.
String ob2(ob1) Here, the compiler automatically initializes (copies bit by bit) from ob1 to ob2. So we
don’t need to write any constructor for this. However, if object contains a pointer and that is pointing to
external memory (other than object itself), the same problem as mentioned earlier will arise. To solve this
problem, we need to write our own version of the constructor to copy one object’s data to another.
This is often called the copy constructor. (A copy constructor means: it copies/initializes one object with
another object).
Many people get confused about the assignment and initialization of objects. Let us see the code
2) String ob1(“hello”);
String ob2(ob1); // this is initialization, not assignment, copy constructor will be called.
String ob2(ob1) or String ob2=ob1 this instruction may seem like assigning ob1 to ob2, and many people
misunderstand it in this way. Actually, this is initializing ob2 with ob1. The copy constructor will be called.
String ob2(ob1) this statement can be consider as two instructions “String ob2” and “ob2=ob1”;
The first one “String ob2” is said to be declaration of object, here memory space creates for ob2.
The second one “ob2=ob1” initializes ob2 with ob1. Remember, assigning values at the time of declaration
of variables is said to be initialization and not assignment.
Following program explains without overloading copy-constructor, and see how ob2 disturbs the ob1.
#include<stdio.h>
class String
{ char *p;
public:
String() { }
String ( char *p )
{ p=new char[100] ;
strcpy( this->p , p );
}
void change( char *P)
{ strcpy( this->p, p );
}
void show()
{ printf("\n output is %s" , p );
}
};
116 overloading assignment & copy constructor| C-Family
int main()
{ String ob1(“hello”) ;
String ob2(ob1); // ob2 initialized with ob1 by the compiler
ob1.change(“world”); // if ob1 is changed then it also affects to ob2.
ob1.show(); World
ob2.show(); we expecting “hello” but shows “world” this is wrong output
}
As per compiler aspect, when String ob2(ob1) is executed, compiler copies/initializes member to member
within the object but not out-side. So it copies only the address in ob1.p to ob2.p, after this, both pointers
points to same memory (same string “hello”). As a result, if ob1 is changed then also affects to ob2.
The solution is, we need to write the copy constructor as given below
String ob2(ob1);
ob2.String(ob1);
When ob2.set(ob1) is called in the main() function, ob1 is passed as an argument and initialized to ob3.
This instruction can be interpreted as “String ob3=ob1”. Thus our copy-constructor is automatically called
by the compiler to initialize ob3 with ob1. This constructor creates separate memory for ob3 to store the
string. However, creating memory for ob3 is unnecessary because the parameter ob3 automatically deleted
once the function execution finishes.
In this case, for ob3, calling the constructor, creating memory, and then calling the destructor to delete such
memory is useless. Therefore, it is better to avoid calling the copy-constructor & destructor by taking
parameter as a reference variable. The above code re-written as
117 overloading assignment & copy constructor| C-Family
The instruction “String temp = *this” does two things. First, it creates memory for temp, and then the copy
constructor is called. When the copy constructor is called, it un-necessarily creates dynamic memory for
temp. To avoid this unnecessary creation of duplicate objects as parameters when calling a function, as well
as creating duplicate objects while returning, it is better to pass & return references of the object. In this
case, the copy constructor will not be called. This can help improve performance and reduce memory usage.
The above set() and getCopy() should be re-written as
String& getCopy()
{ return *this; // String& temp=*this;
return temp;
}
118 overloading assignment & copy constructor| C-Family
Let us have one complete example, and notice how many times the constructor/destructor will be called
while passing & returning objects between functions.
#include<iostream>
#include<string.h>
using namespace std;
class Test
{ public:
Test()
{ cout<<"\n default constructor";
}
Test( int v)
{ cout<<"\n paramerized constructor";
}
Test( Test &x )
{ cout<<"\n copy constructor";
}
void set( Test x ) //step2: copy ctor will be called here for object “Test X=ob1”
{
} //step3: destructor will be called for “delete X”
Test getCopy()
{ return *this; //step4: copy ctor will be called here for “Test temp=*this”
} //step5: destructor will be called here for “delete temp”
~Test()
{ cout<<"\n destructor";
}
};
int main()
{ Test ob1(10), ob2; //step1: 2 times constructors will be called here for ob1,ob2
ob2.set(ob1);
ob2=ob1.getCopy();
}
Output
parameter constructor ( for ob1 )
default constructor ( for ob 2)
copy constructor ( for x )
destructor ( for x)
copy constructor ( for return *this)
destructor ( for return *this )
destructor ( for ob1)
destructor (for ob2)
119 overloading assignment & copy constructor| C-Family
Conclusion
If objects are smaller and does not required overloading a copy-constructor or destructor (like Date and
Time class objects), It is often more efficient passing and returning a copy of the objects rather than
references. This can improve performance by avoiding implicit pointers for references. In contrast, if objects
are larger or objects involved overloading copy constructor with dynamic memory allocation then references
are the alternative.
Copy constructor and assignment operator works on same meaning, if we need to overload assignment (=)
operator then it is better to overload copy constructor and vice-verse.
Remember: If constructors are involved in dynamic memory allocation, then it is better to write a destructor
to delete such dynamic memory; otherwise, memory leaks may occur. (RAM fills with this crashed memory
dumps)
120 overloading assignment & copy constructor| C-Family
121 overloading cin and cout| C-Family
We have two API library classes called istream and ostream defined in the iostream.h file.
These are stream classes used for input/output operations in C++.
The cin is an object of istream class, and the cout is an object of ostream class.
These are global-scope objects defined globally in iostream.h file under the std namespace.
The istream class is overloaded with functions for reading all types of input values from the keyboard, while
the ostream class is overloaded with functions for writing all types of output values on the screen.
These classes support all data types, including int, float, char, char*, void*, etc.
For each data type, there is a suitable function overloaded in these classes with the operators ‘<<’ and ‘>>’.
The inserter operator (<<) inserts values into the output stream (monitor buffer memory), and the inserted
values are then reflected on the screen. The extractor operator (>>) extracts values from the input
stream(keyboard buffer memory) and assigns them to given variables. These two operators are overloaded
in the istream and ostream classes to support i/o operations on all types of data, this is as shown below.
class ostream
int main() { -------
{ void operator<< ( int k )
{ This function prints int value on the screen
cout<<10; cout.operator<<(10); Here it prints ‘k’ value on the screen
}
cout<<20.50F; cout.operator<<(20.50F); void operator<< ( float k )
{ This function prints float value on the screen
Here it prints ‘k’ value on the screen
}
cout<<”hello”; cout.operator<<(“hello”); void operator<< ( char *k )
} { This function prints string value on the screen
in this way all functions were overloaded in it prints ‘k’ value on the screen as string.
istream & ostream classes. }
--------
};
These inserter operator (<<) and the extractor operator (>>) can be overloaded to print & scan our object
values just as built-in types. For example, printing our class-data objects.
int main()
{ Date ob(10, 5, 2024);
cout<<ob;
}
cout<<ob The compiler can convert this statement into a function call in two ways.
1) cout.operator << ( ob ) // it is a member-function
2) operator<< ( cout , ob ); // it is a non-member-function
122 overloading cin and cout| C-Family
The compiler converts based on the function body found in the program, whether it is a member or non-
member function. If the function body is written inside the class body, it uses the first style. If the function
body is written outside the class body, it uses the second style. It largely depends on you.
In the first style, we would need to write our functions inside the ostream class body, but this is not possible.
Since all library classes are supplied in a pre-compiled format, we can’t add our own functions to the
libraries. I think you got my point: we should write our function in the second style as a non-member.
cout<<ob;
void operator>>( istream &myCin , Date &ob) // here ob must be reference as to follow the call-by-reference
{ cout<<"enter date:"; // the input values reflects in the arguments
myCin>>ob.d>>ob.m>>ob.y;
or
cin>>ob.d>>ob.m>>ob.y;
}
---------------------------------------------------------------------------------------------------------------------------------------------
Let us come to full example for reading and writing Date object values through the cin and cout.
#include<iostream>
using namespace std;
int main()
{ Date ob;
cin>>ob; // operator>> (cin , ob);
cout<<ob; // operator<<(cout , ob);
}
class Date
{ private: int d,m,y;
public: friend void operator<<( ostream &myCout, Date ob); // friend to access private data
friend void operator>>( istream &myCin, Date &ob);
};
void operator<< ( ostream &myCout, Date ob)
{ myCout<<"\ndate is :"<< ob.d <<"-"<<ob.m<<"-"<<ob.y;
OR
cout<<"\ndate is :"<<ob.d <<"-"<<ob.m<<"-"<<ob.y;
}
void operator>> ( istream &myCin, Date &ob) // ob is a reference variable as to follow call-by-reference
{ cout<<"enter date:"; // so the input reflects in the arguments
myCin>>ob.d>>ob.m>>ob.y;
OR
cin>>ob.d>>ob.m>>ob.y;
}
123 overloading cin and cout| C-Family
The operator<<() and operator>>() are declared as friend functions of the class, since they are accessing the
private data (d, m, y) of the class.
The above function operaror<<() prints our Date object as mention in the code. However, it can print only a
single Date object and not multiple objects like cout<<ob1<<ob2, because after printing ob1, the function
does not return the ‘cout’ object to print the next object ob2. The code should be re-written to support
multiple objects as
string class
In C, there is no data type called 'string' to manage strings like int, float, etc. Where strings are represented
using character arrays, and handling them is similar to handling arrays. You may have encountered
challenges while handling strings, such as predicting array size, dynamic memory allocation, accessing strings
with pointers, pointer leak errors, string assignments, finding substrings, comparing strings, and other
related issues.
In C++, the ‘string’ class is provided to handle strings in a more efficient and convenient way compared to
C-style character arrays. The string class abstracts operations like memory management, assignment,
comparison, concatenation, substring searching, and more. All these operations are overloaded within the
class, making string handling much simpler and more flexible. Here we can handle strings just like int and
float types. For example, ob2=ob1 is assignment, ob1+ob2 is concatenation, ob1==ob2 for comparison, etc.
Let us have some examples on strings.
C code for concatenation of two strings C++ code for concatenation of two strings
char a*20+=”hello”; string s1 = ”hello”;
char b*20+=”world”; string s2 = “world”;
char c[20]; string s3;
strcpy( c , a ) ; s3=s1+s2; // we can add like 2 integers
strcat( c , b ); cout<<s3;
printf(“ %s “ , c); // helloworld
C code Comparison of two strings C++ code Comparision of two strings.
#include<stdio.h> #include<iostream>
#include<string.h> using namespace std;
int main() int main()
{ char a[100], b[100]; { string s1 , s2;
printf("enter string1:"); cout<<”enter string1:”;
scanf("%s", a ); cin>>s1;
printf("enter string2:"); cout<<”enter string2:”;
fflush( stdin ); cin>>s2;
scanf("%s", b ); if(s1==s2) // comparing like 2 integers
if( strcmp(a,b)==0) printf("equal"); cout<<"equal";
else printf("not equal"); else cout<<"not equal";
} }
Initialization of strings
char a[100]="hello world"; // this is c-language string initialization.
string s1="hello world"; // initializing string object with string-literal.
string s2=a; // Initializing string object with character array.
string s3=s1; // initializing one string object with another string object.
if( str2.empty()==true )
cout<<”yes”; op: no
else cout<<”no”;
str2.assign(str1 , 3); // error, here str1 must be string literal as “hello”, that is char* type. (not object)
str2.assign(str1.c_str() , 3); // this is alternative solution for above call statement.
------------------------------------------------------------------------------------------------------------------------------------------------
128 String | C-Family
Searching
str.find(substring) : finds substring in str.
str.find(substring , position ): finds the first occurrence of a substring from given position and returns its index
str.find(substring , position, cout): finds the first occurrence of a substring from given position and returns its index
it takes ‘count’ of chars of substring.(not all chars)
string str=”ABCDXY”;
str.find(“XY”); 4 , “XY” found at 4th index.
str.find(“A”); 0, found at 0th index
str.find(‘A’); 0, found at 0th index ( can also be used for single char )
str.find(“PP”); -1 , not found,
str.find(“AB”, 4 ); -1 ( not found), searches from index 4
str.find(“ABCD”, 0, 2 ); 0 ( found), searches for 2 chars “AB” from index 0
str.find(“ABCD”, 0, 2 ); 0 ( found), searches for 3 chars “ABC” from index 0
str.find(“ABCD”, 0, 5 ); -1 (not found), searches for 5 chars “ABCDnull” from index 0
object . insert(index, string, from_postion, no.of chars ); // n characters are insert from position p of s.
syntax: string_object.insert( index , char or char* or string ); // inserts a new string at a specific index position.
eg1) syntax2: str.insert( index , string-object ); // inserts string-object in str at index position
string str1=”ABCDEF”, str2=”XY”;
str1.insert( 3 , str2 ); // inserts str2 at 4th index position in str1
cout<<str1; ABCXYDEF
Syntax) str.insert( index idx , times t , char c ); // inserts ‘c’ repeatedly ‘t’ times in str at index ‘idx’
string str1=”ABCDEF”;
str1.insert( 2, 3, ‘X’); // insert ‘X’ 3 times at 2nd index of str1
cout<< str1; "hexxxllo"
129 String | C-Family
syntax: str1.insert( index1, str2, index2, count ); //reads ‘count’ of chars from str2 from index2 and writes to str1 at
index1.
string str1 = "ABCD";
string str2 = "PQRS";
str1.insert(4, str2, 1, 3); // inserts in st1 from 4th index, takes 3 chars of str2 from index 1.
cout<<str1; //ABCDPQR
------------------------------------------------------------------------------------------------------------------------------------------------
Deleting substring
string_object.erase ( index , count ); // removes ‘count’ of characters from index position.
string str=”ABCDEFGH”;
str.erase(2 , 3); ABFGH , removes 3 characters from index 2
str.erase(); erases total string
str.erase(3); ABC , erases all characters from index 3.
str.erase(0); erases all characters from index 0. (Removes total string)
------------------------------------------------------------------------------------------------------------------------------------------------
replacing strings
str.replace( index, count, newString ) to replace a substring with another.
string str=”ABCD”;
str.replace(0, 0 ,”XYZ”); XYZABCD , replaces 0 chars of ABCD by XYZ at index 0
str.replace(0, 1 ,”XYZ”); XYZBCD , replaces 1 char of ABCD by XYZ at 0 index
str.replace(0, 2 ,”XYZ”); XYZCD , replaces 2 chars of ABCD by XYZ at 0 index
str.replace(0, 3 ,”XYZ”); XYZ , replaces 3 chars of ABCD by XYZ at index 0
str.replace(2, 3 ,”XYZ”); ABXYZ , replaces 3 chars of ABCD by XYZ at index 2
str.replace(2, 1 ,”XYZ”); ABXYZD , replaces 1 char of ABCD by XYZ at index 2
------------------------------------------------------------------------------------------------------------------------------------------------
130 String | C-Family
131 Exception Handling | C-Family
Template
The English word "template" refers to a solid shape or pattern used to create multiple copies from that
shape. For example, making several Xerox copies from an original certificate.
In C++, A template defines generic code that can be used with different types of data. For example, a
template swap() function can be used to swap integers, floats, characters, etc. Suppose you need to write
two swap() functions: one for swapping integers and another for floats. In that case, it is better to write a
single template swap() fn that works for both types, since the code (logic) is the same for int and floats.
Thus template allows you to define generic code (logic that works for all types), which can then be used with
different data types. Templates are a core feature in C++ that supports generic programming.
This eliminates the need to write separate functions or classes for each data type, making the code more
flexible and reusable. Templates are used in two ways: 1. Function Template 2. Class template
syntax for function template is:
template< typename T1 , typename T2, … > // here template , typename are keywords
return_type function_name( parameters_list ) // where T1,T2 are type-name identifiers
{ local_variables_list
-----------------------
-----------------------
return_value;
}
----------------------------------------------------------------------------------------------------------------------------------------------
Let us create template add() function to add two values.
Here, template and typename are keywords, while T is the type identifier.
For the type identifier, we can use any name, similar to how we name variables.
Based on the argument types in function call statements, the compiler generates suitable versions of the
function bodies. In this program, the add() function is called with integers and floats, so the compiler
generates two versions of the function. These two generated functions effectively become overloaded.
After compilation, the code looks like
Here, the template generates two versions of the swap() function for swapping integers and float values.
Totally three functions will be found in this program as function over-loading.
----------------------------------------------------------------------------------------------------------------------------------------------
Template can have more type identifiers where compiler generates suitable function based on calls, for eg.
#include<iostream>
using namespace std;
template< typename T1, typename T2 >
void show( T1 x, T2 y )
{
cout<<"\n output is:"<<x<<" "<<y; // we can’t use printf() statement here
}
int main()
{ int a = 10, b = 20;
float c=10.5f,d=20.5f;
show(a,b); // show(int,int)
show(c,d); // show(float,float);
show(a,c); // show(int,float);
show(c,b); // show(float,int);
show("hello","world"); // show(char*,char*);
}
----------------------------------------------------------------------------------------------------------------------------------------------
Exercise1: write a template function called sort() , which sorts given N elements of int, float, char and string.
Exercise2: Write a template function called show(), which shows single int/float/char, and array of N values.
Exercise3: Write a template function called reverse(), which reverses int, long int, and string.
133 Exception Handling | C-Family
class template
Templates can also be applied to classes. Class templates allow you to create a class that can work with any
data type. The syntax is almost the same as for function templates; however, when declaring a class object,
you need to specify the types explicitly, for example: class-name <int,float>ob1 , <int,char>ob2;
Following template class holds two values, and prints on the screen.
Here class object can hold any type of two values; it works for all built-in types. In this example, int and
float are stored and printed. Template classes vastly used in data structure’s class-libraries like stack,
queue, list, tree, graph, set, etc.
Exception Handling
An exception is a runtime error that forcibly stops our program during execution. It stops our program in the
middle of execution without displaying a proper message. This unexpected action is also referred to as a
program crash or abnormal termination of the program.
Errors are typically classified into three types: 1. Syntax errors, 2. Logical errors, and 3. Runtime errors.
Syntax errors are handled by the compiler. These errors usually involve missing semicolons, missing quotes,
and incorrect use of statements. We don't need to worry about these errors because the compiler catches
them at compile time and reports us. Logical errors occur when a program compiles successfully but
produces incorrect results. For example, writing avg=m1+m2+m3 instead of avg=(m1+m2+m3)/3.
Sometimes, logical errors can also lead to runtime errors.
Runtime errors stop the program in the middle of execution. Examples include divide by zero, array index
out of bounds, file not found, network failure, hardware failure, OS hanging, lack of resources, etc.
Runtime errors also known as "nightmare errors," can create serious issues on the client side. For example,
if a banking or railway reservation application crashes during business hours, it can cause significant
problems. That is why runtime errors are considered as serious problems in the industry. Many testers are
employed to thoroughly test applications in various scenarios before they are delivered to clients.
In C, there were no proper control statements provided to handle exceptions in systematic way. Here
exceptions are handled using if-else statement, For example
int main()
{ int X , Y , Z ;
scanf(“%d%d”, &X , &Y );
Z = X / Y;
printf(“output is %d”, Z );
}
If the input value Y is 0, the computer processor cannot calculate X/0. In such a case, the processor throws
back an error to the operating system. The OS then stops our program at this instruction because, without
calculating X/Y, the value of Z cannot be printed to the screen. The following code demonstrates how these
errors are handled in C using an if-statement.
int main()
{ int X, Y, Z;
scanf(“%d%d”, &X, &Y);
if( Y==0 )
{ printf(“error, denominator is zero”);
return;
}
Z=X/Y;
printf(“output is %d”, Z);
}
Handling various types of exceptions using if-else statements can be complex and limited.
Therefore, C++ provides special control statements to handle exceptions more effectively.
The control statements are: try, catch, throw.
A try block can have multiple input validations and throw statements when one input
validation is depended on another validation. Let us have one demo program.
This program accepts time from keyboard and checks whether it is valid or not.
#include<stdio.h>
int main()
{ int h, m, s;
try
{ printf("\n enter hours :");
scanf("%d", &h);
if(h<0 || h>12)
throw 1;
// Control never reaches this point if 'hours' is invalid.
printf("\n enter minutes :");
scanf("%d", &m);
if(m<0 || m>59)
throw 2;
// Control never reaches this point if 'minutes' is invalid.
printf("\n enter seconds :");
scanf("%d", &s);
if(s<0 || s>59)
throw 3;
}
137 Exception Handling | C-Family
catch( int v )
{ if(v==1) printf("invalid hours");
else if(v==2) printf("invalid minutes");
else if(v==3) printf("invalid seconds");
return 0;
}
printf("\n u entered time is valid, have a nice day");
return 0;
}
We can have more than one check and throw statement in a try block where one input depends on another.
If the hours input is invalid, the program won't scan the minutes. It is unnecessary scanning the minutes
when the hours is invalid (so bypassed). Similarly, if the minutes input is invalid, the program won't scan the
seconds.
---------------------------------------------------------------------------------------------------------------------------------------------
The complete syntax and usage of the try, catch, and throw statements are given below:
try
{ ----------
----------
if( condition1 )
throw type1_error_value;
----------
----------
if( condition2 )
throw type2_error_value;
----------
----------
}
catch( error_type1 parameter)
{ ----------
Exception handling code here
-----------
}
catch( error_type2 parameter)
{ -----------
Exception handling code here
-----------
}
catch( … ) // three dots, this is the default catch block like in switch statement ( this is optional block also )
{ --------------
this is the last catch block, catches all errors which are not caught by above catch blocks
}
Here is the detailed explanation how the try-catch statement executes in the program.
Single try-block can have multiple catch blocks; different catch blocks to handle different types of errors.
In the try block, errors are examined based on the input values. If any error is detected, the throw statement
throws the control to the corresponding catch-block along with the error value. The thrown value is caught
by the corresponding catch block's parameter, where the exception is handled (resolved).
138 Exception Handling | C-Family
When an error is thrown in the try block, control immediately jumps to the appropriate catch block, and the
remaining bottom statements in the try block are skipped by the compiler. (Observe arrow lines)
You might wonder whether the program continues after the execution of the catch block or stops there.
That depends on the instructions written in the catch block. If you use the exit() function, the program
terminates at that point. If you use the return statement, the function terminates and returns the control to
main() function. If these two are not used, then program continues with the instructions following the last
catch block. Note that only one catch block will be executed, and the rest will be skipped.
If no catch block matches the error value, the final default catch block catch(…) will be executed. Here three
dots like and so on.
This is an optional and default catch-block used to handle unexpected errors which are not caught by the
above catch blocks.
If these blocks is not provided and no catch block suites above, the exception is considered unhandled.
In this case compiler calls the implicit function terminate() or abort() to stop the program. These functions
terminates program forcibly in the middle of execution.
In C++, for exception handling, there is a built-in mechanism that utilizes the stack data structure, library
functions, and API classes. For example, the terminate() function is automatically called when there is no
way to move the control after an exception raised.
You may wonder whether such complex systems are necessary to handle simple errors. Certainly not.
In fact, real-time applications often encounter complex scenarios such as nested errors, bypassing errors,
handling repeated errors, throwing errors between classes, and more. So, to handle these complex types of
errors, this system was provided.
If no errors are found in the try block, control jumps to the bottom instructions after the last catch block,
and the program continues smoothly. The execution of try-catch block is somewhat similar to the execution
of a switch-case statement. Specifying parameter names at catch-blocks are optional.
The throwing error-values in try-block can be any built-in or class-types. In professional programming,
mostly the values are class objects. Let us see demo program throwing exception as a class object
observe here we did not get observe here we did not get observe here we did not get
reached check point 2 reached check point 3 reached check point 3
reached check point 3 reached check point 4 reached check point 4
Demo: Scanning two values from the keyboard and printing their result of division.
The program checks the denominator before performing the division and throws an error if it is invalid.
#include<stdio.h>
int main()
{ int a, b, c=-1;
try
{ printf("\n enter two values:");
scanf("%d%d", &a, &b);
if(b==0)
throw b;
c=a/b;
}
catch(int)
{ printf("\n denominator should be zero");
}
140 Exception Handling | C-Family
catch(...)
{ printf("\n some unknown error found");
}
printf("\n the output is %d",c);
return 0;
}
In this program, catch() block showing an error but not stopping the program using return/exit() statement.
So output will be -1 as initial value of ‘c’.
----------------------------------------------------------------------------------------------------------------------------------------------
Demo: Scanning month from keyboard and printing total days in that month, if input month not in 1 to 12
then shows an error and again scans until valid input entered.
#include<stdio.h>
int main()
{ int month;
int days[]={0,31,28,31,30,31,30,31,31,30,31,30,31};
while(true)
{ try
{ printf("\n\n enter month value:");
scanf("%d", &month);
if( month<0 || month>12 )
throw month;
break;
}
catch(int m)
{ printf(" the month should not be %d, try again", m);
}
}
printf(" days in month %d is %d", month, days[month] );
return 0;
}
For example, if a technical problem is found in a car, the driver reports it to the owner instead of repairing it
themselves ( not paying from his pockets). In this analogy, the called function is like the driver, and the
calling function is like the owner.
--------------------------------------------------------------------------------------------------------------------------------------------
Modifying above program, here the call statement has not been written inside the try-catch block, so it leads
to program crash if denominator is zero.
#include<stdio.h>
int divide( int a,int b)
{ if(b<=0)
throw b; // throwing exception to the caller-function.
return a/b;
}
int main()
{ divide(10,0); // observe, this call statement should be written inside try-catch block.
}
this program stops abnormally at the instruction a/b, because error is not handling using try-block.
------------------------------------------------------------------ ------------------------------------------------------------------ --------
142 Exception Handling | C-Family
Re-throwing exception
Skipping or bypassing the exception: Using the “throw” statement, we can pass over or skip the exception
without handling it. For example, the inner catch block can pass the exception over to the outer catch block.
This is called re-throwing an exception from the inner catch block to the outer catch block.
Example1 Example2
try try
{ try { try
{ if(k==0) { if(k==0)
throw k; throw k;
} }
catch(int) catch(int)
{ printf(“\n caught at inner catch”); { throw; // re-throwing to outer block
} }
} }
catch() catch()
{ printf(“\n caught at outer catch”); { printf(“\n caught at outer catch”);
} }
output: caught at inner catch output: caught at outer catch
Example3 Example4
try try
{ if(k==0) { try
throw 10; { if(k==0) throw 10;
} }
catch(int) catch(int)
{ throw; // re-throwing to outside { throw; // re-throwing to catch
} }
This is called unhandled exception, because it is }
re-throwing to outside and not catching catch(int)
anywhere. So program gets crashed. { throw; // re-throwing to outside
}
this is also called un exception handling
143 Exception Handling | C-Family
Note: Exact handling of exception is depends upon client specifications rather than developer ideas.
In real-time, some exceptions are simple like out-of-stocks, network-failure, page-not-found, etc.
However, some exceptions are very critical when many systems are involved in the transactions.
For example, bank payments, train reservation, online order booking & payment, etc. Here a lot of code
needs to be written to solve exceptions.
----------------------------------------------------------------------------------------------------------------------------------------------
guess1: int main()
{ throw 0;
}
this is called unhandled exception, so program terminates(crashes)
----------------------------------------------------------------------------------------------------------------------------------------------
145 Exception Handling | C-Family
guess2: int main()
{ try
{ if( k==0) throw 10;
if( k==1) throw 10.5f;
}
catch( int )
{ printf(“ int exception raised”);
}
}
if k==0 then output is: int exception raised
if k==1 then output is: unhandled exception(crashes)
----------------------------------------------------------------------------------------------------------------------------------------------
guess3: int main()
{ ----------------------------
try
{ if( k==0) throw 10;
if( k==1) throw 10.5f;
}
catch( int )
{ printf(“ int exception raised”);
}
catch( … )
{ printf(“ unknown exception raised”);
}
}
if k==0 then output is: int exception raised
if k==1 then output is: unknown exception
----------------------------------------------------------------------------------------------------------------------------------------------
guess4: int main()
{ ---------------------------
try
{ if( k==0) throw 10;
if( k==1) throw 10.5f;
}
catch( int )
{ printf(" int exception raised");
}
catch(...)
{ throw;
}
}
if k==0 then output is: int exception raised
if k==1 then output is: crash (unhandled exception)
The ‘throw’ statement throws the exception outside of the catch block (passes the exception). Since there is
no outer catch block to catch and handle it, this leads to an unhandled exception.
----------------------------------------------------------------------------------------------------------------------------------------------
146 Exception Handling | C-Family
Inheritance
Inheritance is a core concept of Object-Oriented Programming (OOP) that allows one class to inherit the
properties and behaviors of another class. This is similar to how a child inherits assets from their parents,
such as cars, homes, or land. The class whose properties are being shared is referred to as the base class,
while the class that inherits these properties is known as the derived class. Nowadays, for easier
understanding, the base class is often called the parent class, and the derived class is often called the child
class. All properties of the parent class are inherited by the child class, and they can be accessed as if they
were local members in the child class. Let us see the syntax how to derive a class
class X
{ ---------
---------
};
class Y : access-type X // this inherit access-type can be private/public/protected
{ ---------
---------
};
Here, class X is referred to as the base class or parent class, and class Y is referred to as the derived class or
child class. class X is independent and does not know about class Y. There is no relationship or dependency
of class X on class Y, whereas class Y depends on class X because it inherits its properties.
The inherit access-type for whole class can be private, public, or protected. But most of the time public is
used. For a while, we ignore this inherit access-type. Let us see different examples one by one
Demo1:
class Parent
{ private: int X;
public: int Y;
};
ob
class Child : public Parent
{ public: int Z; X Y Z
};
int main()
{ Child ob;
----------
----------
}
Since the Child class inherits (derives) all members of the Parent regardless of whether they are public or
private, the variables X and Y are inherited by the Child and become part of it. Therefore, space for X and Y is
allocated alongside Z in the object ‘ob’. This is as shown above picture how the object ‘ob’ occupies in
memory.
You might think that private members are strictly private to the class and cannot be inherited. In fact, they
are inherited by the child class but are not directly accessible in the child. Therefore, space for the private
members of the parent class is created in the child class object. We know that private members are accessed
through public interface functions from outside the class, and this rule also applies in the case of
inheritance. Let us consider one example
148 Inheritance | C-Family
class Parent
{ private: int X;
public: int Y;
};
class Child : public Parent
{ public: int Z;
void show()
{ printf(“%d %d %d”, X, Y, Z ); // error, X is private to Parent, so not accessible at Child
}
};
The variable X is private to the parent class, so it can’t be accessed outside, including by child classes.
In case access is needed, there are three options: the first option is, use public interface functions,
specifically set() and get(). This has already been discussed at the beginning of this book. The second option
is to change the private access to public access, which would allow access anywhere in the program.
However, changing private to public is not a good choice in all cases.
The best third option is to change the access type from private to protected. Protected works similarly to
private but allows access in child classes. Thus, protected is a good choice when members need to be
accessed only in the parent and child classes, but not from other parts of the program.
Following example shows how to access private members through public set() and get().
class Parent
{ private: int X;
public: int Y;
int getX() { return X; }
};
class Child : public Parent
{ public: int Z;
void show()
{ printf(“%d %d %d”, getX() , Y, Z ); // the function getX() returns the private of X
}
};
Here the getX() function is in public and it returns the X value of Parent class, in this way private are
accessed through public interface functions.
Protected works same as private but it allows to access only in parent and child but not outside.
Actually, in inheritance concepts, protected access type commonly used instead of private.
Example for protected access type.
class Parent
{ protected: int X;
public: int Y;
};
class Child : public Parent
{ public: int Z;
void show()
{ printf(“%d %d %d”, X , Y, Z ); // no error, protected of parent can be accessed in child
}
};
Protected is more convenient access-type which is commonly used in inheritance.
------------------------------------------------------------------------------------------------------------------------------------------------
149 Inheritance | C-Family
Demo3: Let us have one more example accessing protected members at main() function.
class Parent
{ protected: int X;
public: Parent() { X=100; }
void print()
{ printf(“%d “ , X );
}
};
class Child : public Parent
{ protected: int Y;
public: Child() { Y=200; }
void show()
{ printf(“ %d %d“ , X, Y );
}
};
int main()
{ Parent ob1;
ob1.X=100; // error, protected members can’t be accessed outside of class
ob1.print(); // calls the print() function of Parent-class
ob1.show(); // error, there is no show() function in Parent-class
Child ob2;
ob2.print(); // calls the print() function of Parent-class, as it inherited to the child.
ob2.show(); // calls the show() of Child-class
}
As the child class inherits members from the parent class, these members become part of the child class as
well. This means that, using an object of the child class, we can access both the child and parent class
members in the main() function, provided these members are public. For example, ob2.print() calls the
parent class function using the child class object ob2.
Note that both classes have their own default constructors. When a child object is created, the parent class
constructor is executed first, followed by the child class constructor. (We will discuss about constructors in
the next topics.)
------------------------------------------------------------------------------------------------------------------------------------------------
Example, accessing public members of parent and child through child class object at main() function.
}
};
class Result: public Marks
{ protected: int total, average;
public:
void find()
{ total=marks1+marks2;
average=total/2;
}
void showResult()
{ printf("\n %d %d %d %d", marks1, marks2, total, average);
// or
showMarks(); or this->showMarks(); // parent class fn called with current object (ob.showMarks)
printf(",total=%d,avg=%d", total, average);
}
};
int main()
{ Result ob;
ob.scan();
ob.find();
ob.showResult();
}
here the function showResult() is calling the parent class function showMarks() to print the marks.
The showResult() is calling with object ‘ob’ , then you may wonder on which object the showMarks() is
calling here. Actually, this is also calling with same object ‘ob’ through ‘this’ pointer.
----------------------------------------------------------------------------------------------------------------------------------------------
151 Inheritance | C-Family
Following example finds area of Rectangle and Triangle.
The Rectangle area is : length*breadth Shape
Shape is the parent class shared by child classes Rectangle and Triangle.
The common properties of child classes are defined in parent ‘Shape’ so that they can be shared.
This reduces the repetition of code and increase the flexibility of code.
Let us see following code
#include<stdio.h>
class Shape
{ protected: int length, breadth, area;
public:
void scan()
{ printf("enter lenght & breadth:");
scanf("%d%d", &length, &breadth);
}
void show()
{ printf("\n area is %d", area );
}
};
class Rectangle: public Shape
{ public:
void find()
{ area=length*breadth;
}
};
class Triangle: public Shape
{ public:
void find()
{ area=0.5*length*breadth;
}
};
int main()
{ Rectangle ob1;
ob1.scan();
ob1.find();
ob1.show();
Triangle ob2;
ob2.scan();
ob2.find();
ob2.show();
}
exercise: Try this program without using inheritance concept (do not use Shape class)
---------------------------------------------------------------------------------------------------------------------------------------------
152 Inheritance | C-Family
Inherit access-type
We can specify the access-type while inheriting another class. Let us see following syntax.
class Parent
{ -------------
------------- This is called inherit access type
};
class Child : public Parent
{ -------------
-------------
};
The inherit access type can be private or public or protected. But many times public is used by the
programmers. Remember default access type is private (if we don’t mention any type).
Let us see how this behaves in the program.
154 Inheritance | C-Family
int incrementTime(int n)
{ int prev,days=0;
days=n/(24*3600); // counting days if hr>24
n=n%(24*3600); // if more than one day
prev=hour*3600+min*60+sec;
if( prev<=12*3600 && prev+n>12*3600)
{ if(*amPm=='P') amPm="AM";
else amPm="PM";
days++;
}
n=n+prev; hour=n/3600;
n=n%3600; min=n/60; sec=n%60;
if(hour>12) hour=hour%12;
return days;
}
};
class DateTime
{ Date dt; Time tt;
public:
DateTime(int day, int month, int year, int h,int m,int s, char *amPm)
{ dt.setDate(day,month,year);
tt.setTime(h,m,s,amPm);
}
void incrementTime(int n)
{ int k=tt.incrementTime(n);
dt.incrementDate(k);
}
void incrementDate(int n)
{ dt.incrementDate(n);
}
void showDateTime()
{ dt.showDate();
tt.showTime();
}
};
int main()
{ DateTime ob(10,5,2024, 9,4,50,"PM");
ob.showDateTime();
ob.incrementTime( 7200 ); // 2hours
cout<<"\n\n date and time is, after adding 2hr ";
ob.showDateTime();
ob.incrementDate(5);
ob.showDateTime();
}
------------------------------------------------------------------------------------------------------------------------------------------------
156 Inheritance | C-Family
The above code can be written using more than one level of inheritance. Complete code yourself.
Date Date
{
};
Date Time : public Date
{
};
Date DateTime: public Time
{
};
int main()
{
}
-----------------------------------------------------------------------------------------------------------------------------------------------
157 Inheritance | C-Family
class Child : private Parent class Child : protected Parent class Child: public Parent
{ X is not accessible here; { X is not accessible here ; { X is not accessible;
Y, Z are accessible but Y , Z are accessible but Y , Z are accessible and
turns into private here turns into protected here ; no conversion is made;
}; }; };
Security can be increased but not decreased. This means public members can be converted to protected or
private, and protected members can be changed to private. However, the reverse conversion is not possible.
----------------------------------------------------------------------------------------------------------------------------------------------
Example with access type: This demo program explains how parent members are inherited and
converted to the given access type in the child class. For example, if a parent has a car and gives it to the
child with the condition to use it personally/privately, it means the child can use it freely but cannot give it
to others.
Child c;
class Child : private Parent
c.x=10; // error, private
{ void show()
c.y=20; // error, private
{ x=100; // error, private inaccessible
c.z=30; // error, private
y=200; // accessible, and turns into private here
}
z=300; // accessible, and turns into private here
The object ‘p’ belongs to Parent class, where p.x is
} private, p.y is protected, p.z is public;
}; The object ‘c’ belongs to Child class, here all c.x , c.y, c.z
are private, so they are not accessible outside class.
158 Inheritance | C-Family
Example with protected access type
If access type is protected, it means the child and grandchild ( all descendants) can use it freely but not by
other classes.
Child c;
class Child : Protected Parent
c.x=10; // error, private not accessible
{ void show()
c.y=20; // error, protected not accessible
{ x=100; // error, private inaccessible
c.z=30; // error, protected not accessible
y=200; // accessible, and turns into protected here
}
z=300; // accessible, and turns into protected here
The object ‘p’ belongs to Parent class, where p.x is
} private, p.y is protected, p.z is public;
}; The object ‘c’ belongs to Child class, here c.y, c.z
are protected, so they are not accessible outside class
Child c ;
class Child : public Parent
c.x = 10; // error, private
{ void show()
c.y = 20; // error, protected
{ x=100; // error, private inaccessible
c.z = 30; // accessible, still public
y=200; // accessible, remains same access-type
}
z=300; // accessible, remains same access-type
The object ‘p’ belongs to Parent class, where p.x is
} private, p.y is protected, p.z is public;
}; The object ‘c’ belongs to Child class, here c.x, c.y, c.z
remains same access type as in parent.
159 Inheritance | C-Family
Types of inheritance
In inheritance, classes may inherit in different styles such as one-to-one, one-to-many, many-to-one, and
many-to-many. These are mainly categorized into four types: Single-level, Multi-level, Hierarchical, and
Multiple (Hybrid)
class B : public A
class B : public A {
{ };
};
class C : public B
{
};
In single-level inheritance, one class inherits from another single class, whereas in multi-level inheritance,
more than two classes may be involved. In multiple inheritance, more than two classes are inherited at a
time. Hierarchical inheritance is also referred to as single-level or multi-level because, for example, class A is
shared by classes B and C. Here, separate copies of A are given to both B and C, and there is no relation
between B and C. This is as given below picture.
A A A
B C B C
160 Inheritance | C-Family
Here, two variables named X are inherited by the child class C. One X is from class A, and the other is from
class B. As a result, the compiler unable to choose which base class's X to be selected, leading to an
ambiguity error. The scope resolution operator is required to resolve this ambiguity, as shown in the
example above such as A::X and B::X.
If the child class C also has a member named X, by default local member get accessed directly without the
scope resolution operator. Let us see following example
class B class C
class D
In this case, class A is inherited twice in class D through class B and class C, resulting in two copies of class A
in D, which leads to an ambiguity error.
The solution is to add the virtual keyword when inheriting class A in both class B and class C. Actually, this is
a compiler issue — the compiler itself should have been designed to handle this problem. Instead, this
responsibility has been passed on to C++ programmers.
In fact, the child class constructor automatically calls the default constructor of the parent class to initialize
its members. So, the child class constructor itself calls the parent class constructor. This call statement is
automatically inserted by the compiler at the start of every child class constructor. So every child class
constructor implicitly calls the parent class default constructor at first line. When a child class object is
created, control first transfers to the child class constructor, but before executing its body, control is
redirected to the parent class constructor. After the parent class constructor completes, control returns to
continue executing the child class constructor. So constructors are executed from top to bottom the order
how they are derived, whereas destructor are executed from bottom to top in reverse order of constructors.
Remember, by default, the compiler only calls the default constructor of the base class. To call a
parameterized constructor of the base class, we need to use a specific syntax. Following example shows how
parent class constructor will be called in the program.
#include<iostream> #include<iostream>
using namespace std; using namespace std;
class Parent class Parent
{ protected: int X; { protected: int X;
public: public:
Parent() Parent()
{ X=10; { X=10;
} }
}; };
class Child : public Parent class Child : public Parent
{ protected: int Y; { protected: int Y;
public: public:
Child() Child()
{ Y=30; { Parent(); // this line adds by compiler
} Y=30;
Child(int Y) }
{ this->Y=Y; Child(int Y)
} { Parent(); // this line also adds by compiler
void show() this->Y=Y;
{ cout<<”\n”<< X<<" "<<Y; }
} void show()
}; { cout<<”\n”<<X<<" "<<Y;
int main() }
{ Child ob; };
ob.show(); int main()
} { Child ob;
output: 10 20 ob.show();
}
169 Inheritance | C-Family
Calling parameterized constructor: Following example explains how parent class parameterized
constructor is called from its child class. The syntax is:
child-class-name ( parameters list ) : parent-class-name ( arguments list )
{ -----------
-----------
}
Initializing more than one parent class in class Child : public Parent1 , public Parent2
multiple inheritance { public: int Z;
Child ( int X, int Y, int Z ):Parent1(X) , Parent2(Y)
class Parent1 { this->Z=Z;
{ public: int X; }
Parent1 ( int X ) void show()
{ this->X=X; { cout<<X<<Y<<Z;
} }
}; };
class Parent2
{ public: int Y; int main()
Parent2 ( int Y ) { Child ob(10,20,30);
{ this->Y=Y; ob.show();
} }
};
170 Inheritance | C-Family
Following example finds area of Rectangle and Triangle using parameterized constructors.
Destructors in inheritance
Constructors are called from top class to bottom class in the order they are derived in the program.
You might wonder why constructors aren’t called from bottom to top instead. Technically, child class
members sometimes depend on parent class member’s data. For example, the parent class opens a file and
the child class writes content to it. Let us take another example, if a parent class dynamically creates the
rows of a 2D array and the child class creates the columns, it would be necessary to create the rows first.
Therefore, it is wise to initialize the parent class before the child class.
In case of destructors, only one destructor is allowed per class, and these destructors are executed one by
one from bottom to top, in reverse order of the constructors. For instance, we cannot delete the rows
created by the parent class without first deleting the columns created by the child class.
Following example explains the order how constructers are called in the program.
#include<iostream>
using namespace std;
class Parent
{ public:
Parent()
{ cout<<"\nParent class Constructor";
}
~Parent()
{ cout<<"\nParent class Destructor";
}
};
class Child : public Parent
{ public:
Child()
{ cout<<"\nChild class constructor";
}
~Child()
{ cout<<"\nChild class Destructor";
}
};
int main()
{ Child ob;
}
output:
Parent class Constructor
Child class constructor
Child class Destructor
Parent class Destructor
Note: Destructors do not take parameters because there is nothing to do with a dying
object except deleting already allocated resources, like files, dynamically allocated
memory, etc.
172 Inheritance | C-Family
Example for multiple inheritance, it shows how constructor and destructor are executed in
multiple inheritance. It calls same order how they are derived by the child.
#include<iostream>
using namespace std;
class Parent1
{ public:
Parent1()
{ cout<<"\nParent1 class Constructor";
}
~Parent1()
{ cout <<"\nParent1 class Destructor";
}
};
class Parent2
{ public:
Parent2()
{ cout<<"\nParent2 class Constructor";
}
~Parent2()
{ cout<<"\nParent2 class Destructor";
}
};
output:
Parent1 class Constructor
Parent2 class Constructor
Child class constructor
Child class Destructor
Parent2 class Destructor
Parent1 class Destructor
173 Inheritance | C-Family
Develop yourself 4 applications to check all types of inheritances. These 4 models specified given below
with suitable example and also main() function provided. According to main() function complete classes.
class Syllabus: subject-name ( let C++)
class Student: student-name, subject-name (Ram, C++)
class Teacher: teacher-name, subject-name (Sita, C++)
Student
Virtual functions
A virtual function is a function that is declared in the base (parent) class, either with or without a body, and
is redefined in the derived (child) class. Let's consider a real-life example to understand the need for virtual
functions.
In a development environment, different classes may be written by different people. Here, let's assume that
the Samsung and Nokia classes are each written by different individuals though both belong to same app.
There is no guarantee that both developers will give the same name for the function showPrice() as shown
above example. It’s possible they might choose different names. If the same name is used, it simplifies the
work for those using these classes in the main() function. (Easy to remember the name and also simplifies
the code)
Generally, such problems can be addressed using inheritance. In inheritance, common data properties,
common calculation functions, and common interface functions are defined in the base class, while
individual properties are defined in the derived classes. By using inheritance and virtual functions, we can
solve above problem as follows
class Shape
{ virtual void showPrice()=0; // this is virtual function.
};
class Samsung : public Phone
{ void showPrice()
{ printf(“ price is %d”, 10000);
}
};
class Nokia : public Phone
{ void showPrice()
{ printf(“ price is %d”, 12000);
}
};
In a development environment, the base class (root class) is often written by experienced developers who
define common interface functions used by derived classes. Derived classes are typically written by the next
level programmers, who implement the functions specified in the base class interface.
In the example above, showPrice() is a common interface function used in the derived classes.
These interface functions must be redefined (overridden) in the derived classes as needed.
Generally, these interface functions are defined as virtual functions, and they can be written with or without
a body. Most of the time, virtual functions are defined without a body, as shown in the example above
(assigned with 0, which indicates that the function body is not provided). This declaration forces or guides
the programmer to use the same interface name for the functions that override it in derived classes later.
It forces the programmer by showing a compile-time error if they forget to override it in the derived class.
If virtual function has body then compiler does not force the program to override in the derived classes.
Providing or enforcing a common interface for all classes is essentially an implementation of polymorphism.
176 Virtual functions | C-Family
Act of virtual function
A virtual function is a function declared in the parent class, either with or without a body, and redefined in
the child class. Here, a parent class pointer can point to any child class object, and based on the pointer
pointing object, the virtual function of that class is called. The compiler implicitly maintains a table called a
Vtable to store virtual function addresses and calls them by searching in this table based on the object
pointed to by the pointer.
Virtual function is defined in two ways in the parent class, with and without body. If virtual function has
body then compiler does not force to redefine in the child class. If function has no body then compiler forces
to override in the child class. In this case, this function is also called pure virtual function(assigned with zero).
As we know, the overridden function in the child class must have the same function name, same parameter
types, same parameter count, and same return type as in the parent class (same proto-type).
The compiler does not consider whether the function is private or public; however, if it is private, it cannot
be called from outside the class.
Virtual functions are used to develop dynamic polymorphism, where the function call statement is linked
with the function body at the time of running an application. Based on the input type, compiler calls the
appropriate class version. Let us see following example
#include<stdio.h>
class Parent
{ public:
virtual void show() // remember, virtual function can be written with or without body
{ printf("\n From Child class, virtual show() function ");
}
void display()
{ printf("\n From Parent class, non-virtual display() function");
}
};
class Child : public Parent
{ public:
void show()
{ printf("\n From Child class, virtual show() function");
}
void display()
{ printf("\n From Child class, non-virtual display() function");
}
};
int main()
{ Parent *ptr; Child ob;
ptr=&ob;
ptr->show(); From Child class, virtual show() function
ptr->display(); From Parent class, non-virtual display() function
}
The instruction ptr->show() calls the child-class version instead of the parent-class version. Since this
function is virtual, the virtual mechanism is enabled, prompting the compiler to insert code that searches for
the actual type of the object pointed to by ptr. Based on the type of object that ptr points to, the functions
of that class are called.
177 Virtual functions | C-Family
In contrast, the instruction ptr->display() calls the parent-class version instead of the child-class version
because display() is a normal member function, and the virtual mechanism is not enabled.
Thus, the compiler calls the function based on the type of ptr rather than the type of the object it points to.
Let us take one more practical example
#include<stdio.h>
class Shape Shape
void showArea()
{ printf("area is %f", area);
}
};
class Rectangle : public Shape
{ public:
void findArea()
{ area=length*breadth;
}
};
class Triangle : public Shape
{ public:
void findArea()
{ area=0.5f*length*breadth;
}
};
int main()
{ Shape *ptr;
int choice;
printf("enter rectangle/triangle [1/2] :");
scanf("%d", &choice);
if( choice==1 ) ptr=new Rectangle();
else ptr=new Triangle();
ptr->findArea();
ptr->showArea();
}
Here, ptr can point to either Rectangle or Triangle based on user ‘choice’ input. Depending on the type of
object that ptr points to, the appropriate class version of the findArea() function will be called.
The above virtual function can be written in two ways: either with or without a body, as shown above
178 Virtual functions | C-Family
The declaration virtual void findArea() = 0; defines a pure virtual function, and this declaration forces the
programmer to receive a compile-time error if they forget to override it in the child class
The declaration virtual void findArea() { area = 0; } defines a normal virtual function, and it does not force
the programmer to override it in the child class. If it is not overridden, then the parent version will be called,
just as in normal inheritance.
In multi-level inheritance, the virtual function can be overridden by all child classes relative to its type.
Both the child and grandchild can have their own overridden functions. Don’t worry; the compiler always
selects the appropriate class based on the object type. If the virtual function is not overridden in the child
class, the compiler searches upward direction through the parent, grandparent, and great-grandparent
(ancestor classes) and calls the nearest ancestor class version.
Let us have some examples
Vehicle
#include<stdio.h>
class Vehicle
{ public: Bike Car
virtual void showPrice()
{ printf("\ncost not defined"); Bike200C
}
};
class Bike: public Vehicle
{ public:
virtual void showPrice()
{ printf("\ncost around 1 to 2 lakhs");
}
};
class Bike200cc: public Bike
{
};
class Car: public Vehicle
{
};
int main()
{ Vehicle *ptr;
ptr=new Bike();
ptr->showPrice(); // cost around 1 to 2 lakhs, calls Bike class version
ptr=new Bike200cc();
ptr->showPrice(); // cost around 1 to 2 lakhs, calls Bike class version
ptr=new Car();
ptr->showPrice(); // cost not defined, calls Vehicle class version
}
179 Virtual functions | C-Family
It is important to note that, using a base class pointer, we can call methods of the parent class as well
as the overridden methods of the child class, but not the individual methods of the child class. Let us
consider the following example
#include<stdio.h>
class Parent
{
};
class Child : public Parent
{ public:
void show()
{ printf("hello");
}
};
int m ain()
{ Parent *ptr;
ptr=new Child();
ptr->show(); // error show() not found in Parent
Child ob;
ob.show(); // no error
}
The base class always defines all the interface functions required by the derived classes. These functions are
essential in API programming. If any individual functions are written in the derived classes, they are used by
these interface functions to support in the code. Interface functions are nothing but virtual functions.
---------------------------------------------------------------------------------------------------------------------------------------------
180 Virtual functions | C-Family
This declaration enforces that the programmer must override the function in the child class. Thus, making a
virtual function pure is a way to guarantees that a derived class will provide its own redefinition.
If a class contains a pure virtual function, it is considered incomplete or an abstract class because a pure has
no body. Since an abstract class is incomplete, we cannot create an object of that class. For example:
class Shape // this is called abstract class
{ virtual void findArea()=0;
};
int main()
{ Shape ob; // error, we can’t create object of abstract class.
Shape *ptr; // no error, we can take pointer for abstract class.
------------
}
We cannot create an object of an abstract class because it is incomplete. The class becomes complete when
the pure is implemented in the child class. Still we cannot create an object of a child class if it does not
implement a pure virtual function. In this case, the child class is also considered abstract. This abstract status
can continue through multiple levels of inheritance until the pure is implemented.
We can have a pointer variable of an abstract class because it can point to a fully implemented child class
object. Therefore, it is allowed to have a pointer to an abstract class.
The following example explains a normal virtual function. This function may or may not be overridden in the
child class. If it is not overridden, the parent class version will be called. Here we can create an object of this
parent class.
class Shape // this is complete or concrete class
{ virtual void findArea();
{
}
};
int main()
{ Shape ob; // no error, we can create object of this class.
------------
}
-----------------------------------------------------------------------------------------------------------------------------------------------
181 Virtual functions | C-Family
Virtual Destructor
when a child class object is created, the constructors are executed from the parent class down to the child
class, while destructors are executed in the reverse order. However, in the case of virtual functions, when
using a parent class pointer to point to a child object, the compiler only calls the parent class destructor.
This happens because the destructor is called based on the pointer type rather than the type of the object
being pointed to. The solution is to make the base class destructor virtual. By doing so, the compiler calls all
destructors in the inheritance chain.
Conclusion
Polymorphism is the process by which a common interface is applied to two or more similar (but technically
different) situations, this implementing the “one interface multiple methods” philosophy. Polymorphism is
important because, it can greatly simplify complex systems. A single, well-defined interface is used to access
a number of different but related actions, and artificial complexity is removed. In essence, polymorphism
allows the program is easier to understand and maintain. When related actions are accessed through a
common interface, you have less to remember.
In C++, polymorphism is achieved in two ways: compile-time binding and runtime binding. Function
overloading and operator overloading fall under compile-time binding, while virtual functions fall under
runtime binding. Early binding is fast and efficient but lacks flexibility. Late binding, on the other hand, is
slower because functions are selected based on input values, but it provides greater flexibility, which is
beneficial for large projects.
182 Virtual functions | C-Family
183 C++ File i/o | C-Family
For this purpose, secondary storage devices are used to store the data permanently in the form of files.
These files often called data files. Thus, data file can be defined as collection of data, stored permanently in
secondary storage device. The secondary storage devices such as hard-disk, cd, dvd, pendrive, tape, etc.
Each file is identified by a valid name called file-name. The interaction with files is treated as interaction with
io devices in the computers. Therefore, all secondary memory devices treated as io devices.
Let us consider a menu driven program to automate student marks in a college. Let the marks scanned from
keyboard are stored permanently in a data file called "marks.dat", later, such marks are processed and
stored the result in a separate file called "result.dat" or displayed on the screen. This is depending upon the
requirement of problem. Following picture explains how our programs interact with files.
Program3 Monitor
Input file1: “marks.dat” void main() Displaying record(s) on the screen.
{
----
---- Printer
Input file2: “result.dat”
} Printing record(s) on the printer.
In computer science, files are classified into two types, 1. Data files, 2. Executable program files.
1. Data files: for example, pdf files, jpg image files, mp3 sound files, mp4 video files, business data files,
and program’s source code files like c, cpp, java files, etc.
2. Executable files: for example, .exe, .com, .dll, etc; Contains machine code instructions. Executable files
are created using compilers, whereas data files are created using executable files. In computer, any file is
stored either in text & binary format. All executable files are stored in binary format, whereas data files are
stored in text or binary formats depending on our requirement.
1. Text Format Files: here, the data is stored in the form of ascii values (string format)
2. Binary Format Files: here, the data is stored as it is in program variables (raw format)
184 C++ File i/o | C-Family
Text Files
In text files, everything is stored in the form of ascii values, even numeric data is converted into string
format with its ascii values of each digit and stored in a file. For example, 'k' contained a value 2891,
this number is stored in text file as
Here 50, 56, 57,49 are ascii values of 2, 8, 9,1 respectively. Internally each digit ascii code is again stored in
binary form as shown above (as computer understands only binary values), in this way, the text data is
stored and retrieved from text files. The library functions converts this numeric to text and text to numeric
while storing and reading back from files. These text files are only suitable for public sharing related files
such as document files, help files, message files, source code program files, small data files, configuration
files, etc. In general, these files are handled in two ways in the computer, by writing a special software
program to manage them, or by using ready-made text editor softwares. Using text editors, we can
read/write/modify the text data. We have several text editors like notepad, word pad, ms-word, etc.
In text files, the ‘\n’ character is stored two characters as "\r\n"(unix format), but while reading back, it
reads as single character (\n). The library functions does this job while writing-reading ‘\n’ to files, so we
don’t need to worry about how to read and write this ‘\n’ character to a file.
In text files, the value 26 is inserted as end-of-file mark (this is like null-char ‘\0’ for strings). Here some
people raise a doubt, if file data itself contained 26 like employee age, then how it differentiates with the
end-of-file 26. Our 26 is stored as ‘2’ and ‘6’ as its ascii values 50 & 54, so no conflict between these two.
Binary files
In this kind of file organization, the data is stored as it is in program variables. Here no conversion is made
while storing and reading back unlike text files. Generally, binary files are extensively used for maintaining
similar type of data like employee records or bank accounts, insurance accounts, etc.
In binary i/o, as it is of storing & reading back takes place between the RAM & hard disk, therefore binary
files are faster than text files. At the end of text files, the value 26 is inserted as end-of-file-mark, whereas in
binary files no such value is inserted, where end-of-file mark is known by the file-size.
In case of binary files, we cannot manipulate the data using text editors. For example, take employee
structure: idno | name | age int | char(30) | int . If this structure data is dumped as it is into file, then it
has to be read back as it is. (2byte at a time for idno, 30byte at a time for name, and 2 byte for age)
So, text editors unaware of this user-defined structure format, hence we cannot handle binary files using
text-editors.(text editors are designed to read/write the data only in the form of ascii values of byte by byte)
There should be special software program needed to handle binary files. For example ‘pdf’ file is a binary
format file and cannot be opened in text editor, a special software like Adobe-Reader is used. Similarly, jpg
files, image files, sound files, movie files are managed using special software.
185 C++ File i/o | C-Family
Let us come to file streaming: The total hard disk space is divided into several blocks, where each block size
1024/2048 bytes. This is not fixed size and it may vary. Our file content is divided according to this hard disk
block size and stored in the hard disk. If file size is 3000 bytes then it takes two or more blocks. We can’t do
any insert/delete/modify operations on file data when file is in hard disk, because, the hard disk supports
only block by block reading-writing. So first we dump the file data from hard disk to RAM and then we do
respective operations, later we store back updated data to disk. RAM supports byte-by-byte read-write
operations therefore we can do any operations when data is in RAM.
When we open an existing file, the total file contents would not be dumped into RAM, only the first block
dumped into RAM and then file pointer set to it, the remaining blocks are loaded one by one when file
pointer moves advance. File pointer is a pointer used to read/write file contents. When a file pointer moves
end of first block, the second block loads into same memory (1 st block replaces by 2nd block), in this way files
data loads into RAM and operated, this process is called file-streaming and managed with help of operating
system. For random file organizations, the blocks are loaded & replaced randomly as per movement of file
pointer. OS provides this file streaming facility to move the file-data from disk-to-RAM and RAM-to-disk.
Our C++ API classes interact with OS, we don’t need to bother about how to manage this file-streaming.
Stream i/o array of bytes memory + read() fn + write() fn + open() fn + close() fn + other functions.
This array of bytes memory is also called buffer or stream-memory with all functionality.
In C++ for handling file stream, there are 3 predefined classes with plenty of functions available.
ifstream class: this is for Input file stream, used for reading data from files.
ofstream class: this is for output file stream, used for writing data to files.
fstream class: this is for both input and output file stream, used for both i/o operations on same file.
These 3 classes are defined in a header file called “fstream.h”.
So we need to include this file in our program as: #include <fstream> or #include <fstream.h>
ifstream class is derived from istream, and this istream class is again derived from ios class.
ofstream class is derived from ostream, and this ostream class is again derived from ios class.
Let us see class hierarchy
ios
istream ostream
ifstream ofstream
fstream
186 C++ File i/o | C-Family
We have already learned about classes istream and ostream, these are used for console i/o to read-write
values from keyboard-screen using cin/cout. These classes have various functions to convert numeric data to
text and text data to numeric. The ios class has various flags which are used while opening files.
We can do bitwise OR operator on these flags. For example, “ ios::in|ios::out ” allows both read-write
operations. The flags “ ios::in|ios::binary ” opens a file for reading with binary mode.
closing a file
The function close() is used to close an opened file, after completion of updating file content, it must be
closed. This operation involves in updating file contents on disk (saving back updated data to disk) and also
releases/deletes buffer & file-stream in the RAM. If file is opened in read-mode, it does not required to store
back in the disk, it only clears from the RAM.
188 C++ File i/o | C-Family
Example1
Scans input values one by one from keyboard until last input is zero, writes each scanned value to disk.
Later reads all such values one by one from disk and prints on the screen.
20 30 40 45 56 23 34 0 ⤶ 20 30 40 45 56 23 34
#include<fstream>
#include<iostream>
using namespace std;
int main()
{ ofstream fout; ifstream fin; int n;
fout.open("sample.txt"); // opening file in write-mode
if( !fout )
{ cout<<"error, file not opened";
return 0;
}
while(1)
{ cout<<"enter a value [at end 0]:";
cin>>n; // reading int value from keyboard
if(n==0)break;
fout<<n<<" "; // writs n value to disk using file object ‘fout’. (also adds space between each value )
}
fout.close();
fin.open("sample.txt"); // opening same file in read-mode
if(!fin)
{ cout<<"error, file not opened";
return 0;
}
while(1)
{ fin>>n; // reading an integer value from file
if(fin.eof()) break; // if end-of-file reached then stops the program
cout<<n<<"\n"; // showing n value on the screen
}
fin.close();
}
-----------------------------------------------------------------------------------------------------------------------------------------------
Example2
Above program in binary mode
#include<fstream>
#include<iostream>
using namespace std;
int main()
{ int n;
ofstream fout("sample.dat", ios::binary); // opening file with constructor
if( !fout )
{ cout<<"error, file not opened";
return 0;
}
189 C++ File i/o | C-Family
while(1)
{ cout<<"enter a value [at end 0]:";
cin>>n;
if(n==0)break;
fout.write( (char*) &n, sizeof(n) );
}
fout.close();
ifstream fin( "sample.dat" , ios::binary );
if(!fin)
{ cout<<"error, file not opened";
return 0;
}
while(1)
{ fin.read( (char*)&n, sizeof(n) );
if(fin.eof()) break;
cout<<n<<"\n";
}
fin.close();
}
---------------------------------------------------------------------------------------------------------------------------------------
Example3
Copying odd numbers from one text file to another text file
Let our text file “input.txt” contained some even & odd numbers, now read numbers one by one from file
and copy only odd numbers into another file called “output.txt”.
file name: “input.txt” File name:”output.txt”
12 17 20 13 29 30 17 13 29 35 43 27
32 35 40 43 27 20 21 29 31 39 11 3
21 29 31 39 11 12
10 8 2 3
#include<fstream>
#include<iostream>
using namespace std;
int main()
{ ofstream fout; ifstream fin;
char sName[30], dName[30]; int n;
cout<<“enter source & destination file names :”;
gets(sName); gets(dName);
fin.open(sName);
fout.open( dName) ;
if( !fin || !fout)
{ cout<<"error, file(s) not found";
return 0;
}
while(1)
{ fin>>n; // reading an integer from file
if( fin.eof()==true ) break;
if(n%2==1) fout<<n<<” “; // if odd number then writes to file
}
fin.close(); fout.close(); // saves onto disk
}
190 C++ File i/o | C-Family
Example4
Counting upper/lower case alphabets, digits and others in a file
This program counts number of upper case alphabets, lower case alphabets, digits, words and lines in a
given text file. It reads char by char from a given file and checks the each character and counts.
#include<fstream>
#include<iostream>
using namespace std;
int main()
{ ofstream fout; ifstream fin;
int upperCount, lowerCount, digitCount, lineCount, wordCount;
char sName[30], dName[30], ch; int n;
cout<<“enter source file name :”;
gets(sName);
fin.open(sName);
if( !fin )
{ cout<<"error, file not found";
return 0;
}
upperCount=lowerCount=digitCount=lineCount=wordCount=0;
while(1)
{ fin>>ch;
if( fin.eof() ) break;
if( isupper(ch) ) upperCount++;
else if( islower(ch) ) lowerCount++;
else if( isdigit(ch) ) digitCount++;
else if(ch==' ') wordCount++;
else if(ch=='\n')
{ wordCount++;
lineCount++;
}
}
fin.close();
cout<<"lower count = "<<lowerCount;
cout<<"upper count = "<<upperCount;
cout<<"digits count = “ << digitsCount;
cout<<"words count = “ <<wordCount;
cout<<”lines count = “<<lineCount;
}
---------------------------------------------------------------------------------------------------------------------------------------------
Example5
Copying one file content to another file (file can be binary or text)
Note: the binary file organization works for both text/binary format files, this program reads byte by byte
from source file and writes to target file, to read and store each byte value, the suitable data type is char.
#include<fstream>
#include<iostream>
using namespace std;
int main()
{ ofstream fout; ifstream fin;
char sName[30] , dName[30] , ch;
cout<<“enter source & destination file names :”;
gets(sName); gets(dName);
191 C++ File i/o | C-Family
fin.open(sName , ios::binary);
fout.open( dName , ios::binary) ;
if( !fin || !fout )
{ cout<<"error, file(s) not found";
return 0;
}
while(1)
{ fin.read( &ch , sizeof(ch) ); // reading char by char from file
if( fin.eof() ) break;
fout.write( &ch, sizeof(ch) ); // writing char by char to file
}
fin.close(); fout.close();
}
--------------------------------------------------------------------------------------------------------------------------------------------
Example6
Handling student details (in binary file format)
This program accepts student marks from keyboard and inserts each record into a file called “marks.dat”,
later read back and process the result and shows on the screen.
Note: this is demo program, for binary file IO system; here class type is used.
input: enter idno (0 to stop): 101⤶
enter name: Srihari⤶
enter marks1 , marks2: 66 77⤶
enter idno (0 to stop): 102⤶
enter name: Narahari⤶
enter marks1 , marks2: 88 99⤶
enter idno (0 to stop): 0⤶
#include<fstream>
#include<iostream>
using namespace std;
class Student
{ int idno, marks1, marks2;
char name[30];
public:
void scanMarksAndStoreToFile()
{ ofstream file;
file.open("student.dat", ios::binary|ios::app); // ios::app appends records to file
if( !file )
{ cout<<"file not opened";
return;
}
while(1)
{ cout<<"\n enter idno (0 to stop):";
cin>>idno;
if(idno==0) break; // 0 is end of input
cout<<"enter name:";
192 C++ File i/o | C-Family
fflush(stdin);
cin>>name;
cout<<"enter marks1 , marks2:";
cin>>marks1>>marks2;
file.write( (char*)this, sizeof(*this));
}
}
void showFile()
{ ifstream file;
file.open("student.dat", ios::binary);
cout<<"\nidno name marks1 marks2";
cout<<"\n-------------------------------";
if( !file )
{ cout<<"file not opened";
return;
}
while(1)
{ file.read((char*)this, sizeof(*this));
if(file.eof()) break;
cout<<"\n"<<idno<<" "<<name<<" "<<marks1<<" "<<marks2;
}
file.close();
}
};
int main()
{ Student ob;
ob.scanMarksAndStoreToFile();
ob.showFile();
}
----------------------------------------------------------------------------------------------------------------------------------------------
Example7
A menu driven program to handle employee records
This program manages employee information: it supports adding newly joined employee details, deleting
relieving employee record, modifying salary, printing particulars.
Employee details are stored in a separate file called "emp.dat".
in this menu run program, the user can select his choice of operation.
Menu Run
--------------------------------
1. Add new employee
2. Delete record
3. Modify record
4. Print all records
0. Exit
Enter choice [1,2,3,4,0]:
#include<stdio.h>
#include<iostream>
#include<fstream>
using namespace std;
class Employee // employee class
{ int empNo;
char name[30];
float salary;
public:
193 C++ File i/o | C-Family
void appendRecord();
void modifyRecord();
void deleteRecord();
void printRecord(); // fn proto-types
};
// this append() function appends a record at end of file
void Employee::appendRecord()
{ ofstream file;
file.open("emp.dat", ios::binary|ios::app);
if( !file )
{ cout<<"\n Unable to open emp.dat file";
return;
}
cout<<"\n enter employee no:";
cin>>empNo;
cout<<" Enter employee name:";
fflush(stdin);
cin>>name;
cout<<" enter salary :";
cin>>salary;
file.write((char*)this , sizeof(*this));
file.close();
cout<<"\n successfully record added";
}
// --------------------------------------------------------------------------------------------------------------------------
// delete () function. Direct deletion of record is not possible from a file, alternative is, copies all records
// into another temp file except deleting record; later temp file is renamed with the original file name.
void Employee::deleteRecord()
{ ifstream fin; ofstream fout; Employee e;
int eno, found=0, k ;
fin.open("emp.dat", ios::binary );
fout.open("temp.dat", ios::binary );
if( !fin || !fout )
{ cout<<"\n unable to open file";
fin.close(); fout.close(); return;
}
cout<<"\n enter employee number to delete record :";
cin>>eno;
while(1)
{ fin.read((char*)&e,sizeof(e));
if(fin.eof()) break;
if(eno==e.empNo)
found=1; // record is found
else
fout.write((char*)&e,sizeof(e));
}
if(found==1) cout<<"\n Record deleted success fully";
else cout<<"\n Record Not found";
fin.close(); fout.close();
remove("emp.dat"); // deletes old-file from disk
rename("temp.dat","emp.dat");
}
// --------------------------------------------------------------------------------------------------------------------------------------
194 C++ File i/o | C-Family
// Modifying data in a record. First, it searches for modifying record in a file, if record is not found then
// displays error message & returns. If found, then old-salary overwrites by new-salary of a record
void Employee::modifyRecord()
{ Employee e; fstream file;
int found=0 , eno, k, pos;
file.open("emp.dat",ios::binary|ios::in|ios::out);
if(!file)
{ cout<<"\n file not found ";
return;
}
cout<<"\n enter employee number:";
cin>>eno;
while(1)
{ file.read( (char*)&e, sizeof(e));
if( file.eof() ) break;
if(eno==e.empNo)
{ found=1; // record is found
break;
}
}
if(found==0) { cout<<"\n Record not found"; return; }
pos=file.tellg(); // this function returns the current position of read/write pointer
pos=pos-sizeof(e);
file.seekp(pos ,ios::beg); /* move the file pointer one record position back, after reading our search record ,
the file pointer moves to next-record, so to replace our new record , we have to move the file pointer back.
The above code moves like that. */
cout<<"old salary :"<<e.salary;
cout<<"enter new salary:";
cin>>e.salary;
file.write((char*)&e,sizeof(e)); // overwriting old record
file.close();
cout<<"\n address suceessfully modified";
}
// --------------------------------------------------------------------------------------------------------------------------------------
// print function, prints all records
void Employee::printRecord()
{ Employee e; int k, count=0; ifstream file;
file.open("emp.dat",ios::binary);
if( !file )
{ cout<<"\n file not found "; return;
}
while(1)
{ file.read( (char*)&e , sizeof(e) );
if( file.eof() ) break;
cout<<"\n employee number :"<<e.empNo;
cout<<"\n employee name :"<<e.name;
cout<<"\n Salary ::"<<e.salary;
count++;
cout<<"\n-----------------------------------------------";
}
cout<<"\n"<< count<<" records found";
file.close();
}
195 C++ File i/o | C-Family
int main()
{ int choice;
Employee ob;
while(1) // loop to display menu continuously
{ cout<<"\n\n=========================================================";
cout<<"\n 1.append \n 2.delete \n 3.modify\n 4 print all\n 0.exit";
printf("\n Enter choice [1,2,3,4,0]:");
cin>>choice;
switch(choice)
{ case 1: ob.appendRecord(); break;
case 2: ob.deleteRecord(); break;
case 3: ob.modifyRecord(); break;
case 4: ob.printRecord(); break;
case 0: return 0;
}
}
return 0;
}
// ----------------------------------------------------------------------------------------------------------------------------------
196 C++ File i/o | C-Family
C-Family 197 C++ Programs
Also test above class using following main() fn ( this is menu-run program)
int main()
{ Bank ob; int ch;
while(1)
{ printf(“\n 1. Deposit \n2.Withdraw \n3.Show balance \n0.exit”);
printf(“\n Enter choice [1|2|3|4|0] :”);
scanf(“%d”, &ch);
switch(ch)
{ case 1: printf(“enter deposit amount :”);
scanf(“%f”, &amount);
ob.deposit(amount);
break;
void main()
{ DateTime dt;
dt.setDateTime(30,1,2019,11,50,50,”AM”);
dt.showDateTime(); // 30-01-2019 @ 11:50:50 AM
dt.incrementTime(3600);
dt.showDateTime(); // 30-01-2019 @ 12:50:50 AM
dt.showDate(); // 30-01-2019
dt.showTime(); // 12:50:50 AM
dt.showTime24(); // 0:50:50
dt.incrementDate(10); // adding 10days to given date
dt.showDateTime(); // 9-02-2019 @ 12:50:50 AM
dt.setDateTime(30,1,2019,11,50,50,”PM”);
dt.showDateTime(); // 30-01-2019 @ 11:50:50 PM
dt.incrementTime(3600);
C-Family 209 C++ Programs
dt.showDateTime(); // 31-01-2019 @ 12:50:50 AM
}
-----------------------------------------------------------------------------------------------------------------------------------------------
22) Linked list data structure
#include<iostream>
#include<stdio.h>
class LinkedList
{ class Node
{ public:
int data;
Node *next;
Node() { data=0; next=NULL; }
Node(int data) { this->data=data; next=NULL; }
Node* getNext() { return next; }
int getData(){ return data; }
void insertNext(int data)
{ Node *temp;
temp=new Node(data);
temp->next=this->next;
this->next=temp;
}
};
Node *head;
public:
LinkedList()
{ head=new Node(); // creating header node, it is dummy in this program.
}
void insertFirst(int data)
{ head->insertNext(data);
}
void insertLast(int data)
{ Node *temp;
temp=head;
while(temp->next!=NULL)
temp=temp->next;
temp->insertNext(data);
}
void showList()
{ Node *temp;
temp=head->next;
printf("\n list is :");
while(temp)
{ printf("%d ", temp->data);
temp=temp->next;
}
}
C-Family 210 C++ Programs
void deleteFirst()
{ Node *temp;
if(head->next!=NULL)
{ temp=head->next;
head->next=head->next->next;
}
delete temp;
}
void deleteLast()
{ Node *prev,*temp;
temp=head;
if(head->next==NULL)
return;
while(temp->next!=NULL)
{ prev=temp;
temp=temp->next;
}
prev->next=NULL;
delete temp;
}
};
int main()
{ LinkedList ob;
ob.insertFirst(3);
ob.insertFirst(2);
ob.insertFirst(1);
ob.showList();
ob.deleteLast();
ob.showList();
return 0;
}