0% found this document useful (0 votes)
50 views194 pages

Object Oriented Programming IOE

Uploaded by

sagin35722
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
50 views194 pages

Object Oriented Programming IOE

Uploaded by

sagin35722
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 194

Object Oriented Programming

Notes

Pravin Sangroula
May, 2025

Contents
Chapter 1: Introduction to OOP 4
1.1 History of programming languages . . . . . . . . . . . . . . . . . . . . . . 4
1.2 Need of Object Oriented programming . . . . . . . . . . . . . . . . . . . 5
1.2.1 Problems with Procedural Languages . . . . . . . . . . . . . . . . 5
1.2.2 The Object-Oriented Approach . . . . . . . . . . . . . . . . . . . 7
1.3 Object Oriented programming vs procedure oriented programming . . . . 7
1.4 Concepts of object oriented programming . . . . . . . . . . . . . . . . . . 9
1.4.1 Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.4.2 Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.4.3 Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.4.4 Reusability . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.4.5 Creating New Data Types . . . . . . . . . . . . . . . . . . . . . . 11
1.4.6 Polymorphism and Overloading . . . . . . . . . . . . . . . . . . . 11
1.5 Popular object oriented languages . . . . . . . . . . . . . . . . . . . . . . 12
1.6 Advantages of OOP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.7 Disadvantages of OOP . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

Chapter 2: Basics of c++ Programming 14


2.1 C++ Program structure . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.2 Character set and tokens . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.3 Variable declaration and expression . . . . . . . . . . . . . . . . . . . . . 17
2.4 Data types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.5 Type conversion and casting . . . . . . . . . . . . . . . . . . . . . . . . . 25
2.5.1 Automatic Conversions . . . . . . . . . . . . . . . . . . . . . . . . 25
2.5.2 Casts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
2.6 User defined constant const . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.7 Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
2.8 Reference variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
2.9 Conditions and looping . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
2.9.1 Conditions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
2.9.2 Loops: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
2.10 Namespace scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
2.11 Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48

1
CONTENTS Object Oriented Programming

2.11.1 Function Overloading . . . . . . . . . . . . . . . . . . . . . . . . . 50


2.11.2 Inline Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
2.11.3 Defaults Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . 52
2.11.4 Scope and Storage Class: . . . . . . . . . . . . . . . . . . . . . . 53
2.11.5 Pass by reference and Return by reference . . . . . . . . . . . . . 53
2.12 Array, pointer and string . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
2.12.1 Array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
2.12.2 Pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
2.12.3 Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
2.13 Structure and unions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
2.14 Enumeration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
2.15 Dynamic memory allocation . . . . . . . . . . . . . . . . . . . . . . . . . 75

Chapter 3: Objects and Classes 79


3.1 C++ classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
3.2 Objects and the member access . . . . . . . . . . . . . . . . . . . . . . . 81
3.3 Relation of object, class and memory . . . . . . . . . . . . . . . . . . . . 83
3.4 Defining member function . . . . . . . . . . . . . . . . . . . . . . . . . . 84
3.5 Defining outer function inline . . . . . . . . . . . . . . . . . . . . . . . . 86
3.6 Objects as member . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
3.7 Constructors and destructors . . . . . . . . . . . . . . . . . . . . . . . . . 88
3.7.1 Types of Constructor . . . . . . . . . . . . . . . . . . . . . . . . . 88
3.7.2 Destructors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
3.8 Object as function arguments . . . . . . . . . . . . . . . . . . . . . . . . 94
3.9 Returning objects from functions . . . . . . . . . . . . . . . . . . . . . . 95
3.10 Array of objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
3.11 Pointer to objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
3.12 Dynamic memory allocation for objects . . . . . . . . . . . . . . . . . . . 99
3.13 Dynamic constructors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
3.14 Static data member and static member function . . . . . . . . . . . . . . 101
3.15 Constant member functions and constant objects . . . . . . . . . . . . . 104
3.15.1 Constant Member Functions: . . . . . . . . . . . . . . . . . . . . 104
3.16 Friend functions and friend classes . . . . . . . . . . . . . . . . . . . . . . 106

Chapter 4: Operator Overloading 110


4.1 Overloadable and non- overloadable operators . . . . . . . . . . . . . . . 110
4.2 Syntax of operator overloading . . . . . . . . . . . . . . . . . . . . . . . . 111
4.3 Operator overloading using member operator functions . . . . . . . . . . 111
4.4 Operator overloading using non member functions . . . . . . . . . . . . . 111
4.5 Unary operator overloading . . . . . . . . . . . . . . . . . . . . . . . . . 112
4.6 Binary operator overloading . . . . . . . . . . . . . . . . . . . . . . . . . 117
4.7 Type conversion between objects . . . . . . . . . . . . . . . . . . . . . . 130
4.7.1 Conversions Between Basic Types . . . . . . . . . . . . . . . . . . 130
4.7.2 Conversions Between Objects and Basic Types . . . . . . . . . . . 131
4.7.3 Conversions Between Objects of Different Classes . . . . . . . . . 134
4.8 Explicit Constructors in C++ . . . . . . . . . . . . . . . . . . . . . . . . 137

Chapter 5: Inheritance 138


5.1 Base class and derived class . . . . . . . . . . . . . . . . . . . . . . . . . 138

2
CONTENTS Object Oriented Programming

5.2 Protected access specifier . . . . . . . . . . . . . . . . . . . . . . . . . . . 140


5.3 Derived class declaration . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
5.4 Derived Class Declaration . . . . . . . . . . . . . . . . . . . . . . . . . . 142
5.5 Is a relation and Has a relation . . . . . . . . . . . . . . . . . . . . . . . 143
5.6 Public, protected and private inheritance . . . . . . . . . . . . . . . . . . 144
5.7 Member overriding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
5.8 Forms of inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
5.8.1 Single Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
5.8.2 Multiple Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . 148
5.8.3 Multilevel Inheritance . . . . . . . . . . . . . . . . . . . . . . . . 152
5.8.4 Hierarchical Inheritance . . . . . . . . . . . . . . . . . . . . . . . 153
5.8.5 Hybrid Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . 155
5.8.6 Multipath Inheritance . . . . . . . . . . . . . . . . . . . . . . . . 156
5.9 Constructors in derived class . . . . . . . . . . . . . . . . . . . . . . . . . 156
5.9.1 Constructor in Single Inheritance . . . . . . . . . . . . . . . . . . 156
5.9.2 Constructor in Multiple Inheritance . . . . . . . . . . . . . . . . . 157
5.9.3 Passing Arguments to Base Class Constructor . . . . . . . . . . . 158
5.10 Destructor in derived class . . . . . . . . . . . . . . . . . . . . . . . . . . 159
5.10.1 Destructor in Single Inheritance . . . . . . . . . . . . . . . . . . . 160
5.10.2 Destructor in Multiple Inheritance . . . . . . . . . . . . . . . . . 160
5.11 Need of virtual base class . . . . . . . . . . . . . . . . . . . . . . . . . . . 161

Chapter 6: Virtual Functions 164


6.1 Need of virtual function . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
6.2 Late Binding[Run Time Polymorphism] . . . . . . . . . . . . . . . . . . . 168
6.3 Array of Pointers to Base Class . . . . . . . . . . . . . . . . . . . . . . . 168
6.4 Pure virtual functions and abstract class . . . . . . . . . . . . . . . . . . 169
6.5 Virtual Destructors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
6.6 The this Pointer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
6.6.1 Accessing Member Data with this . . . . . . . . . . . . . . . . . . 173
6.6.2 Using this for Returning Values . . . . . . . . . . . . . . . . . . . 173
6.6.3 Using this in Constructor . . . . . . . . . . . . . . . . . . . . . . 174
6.7 Reinterpret cast operator . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
6.8 Run-time type information[RTTI] . . . . . . . . . . . . . . . . . . . . . . 176

Chapter 7: Stream Computation 179


7.1 Input/Output stream class hierarchy . . . . . . . . . . . . . . . . . . . . 179
7.2 Stream Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
7.2.1 Error-Status Bits . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
7.2.2 Inputting Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . 182
7.3 Unformatted Input and Output . . . . . . . . . . . . . . . . . . . . . . . 183
7.4 Formatted Input and Output . . . . . . . . . . . . . . . . . . . . . . . . 184

Chapter 8: Templates 192

Chapter 9: Exception Handling 193

References 194

3
Chapter 1: Introduction to OOP Object Oriented Programming

Chapter 1: Introduction to OOP


1.1 History of programming languages

Year Language Creator(s) Description


1843 Ada Lovelace’s Ada Lovelace Considered the first computer
Algorithm algorithm, designed for
Charles Babbage’s Analytical
Engine.
1940s Plankalkül Konrad Zuse First high-level programming
language, designed for
engineering purposes but not
implemented at the time.
1949 Assembly Various Low-level language that
Language simplifies machine code, first
used in the Electronic Delay
Storage Automatic Calculator
(EDSAC).
1952 Autocode Alick Glennie One of the first compiled
languages, developed for the
Mark 1 computer at the
University of Manchester.
1957 FORTRAN John Backus Designed for numeric and
scientific computing;
considered the first high-level
programming language.
1958 LISP John McCarthy Second-oldest high-level
programming language;
primarily used in artificial
intelligence research.
1959 COBOL Grace Hopper Developed for business data
processing; known for its
English-like syntax.
1964 BASIC John G. Kemeny and Created to enable students in
Thomas E. Kurtz fields other than science and
mathematics to use
computers.
1972 C Dennis Ritchie Developed for system
programming and has
influenced many other
languages.
1983 C++ Bjarne Stroustrup Extension of C with
object-oriented features.
1987 Perl Larry Wall General-purpose Unix
scripting language to make
report processing easier.

4
Chapter 1: Introduction to OOP Object Oriented Programming

Year Language Creator(s) Description


1991 Python Guido van Rossum Emphasizes code readability
and simplicity; widely used in
various domains.
1995 Java James Gosling Designed to have as few
implementation dependencies
as possible; widely used for
building enterprise-scale
applications.
1995 JavaScript Brendan Eich Scripting language that
enables interactive web pages;
an essential part of web
applications.

1.2 Need of Object Oriented programming


Object-oriented programming was developed because limitations were discovered in ear-
lier approaches to programming.

1.2.1 Problems with Procedural Languages


C, Pascal, FORTRAN, and similar languages are procedural languages. That is, each
statement in the language tells the computer to do something. A program in a procedural
language is a list of instructions. For very small programs, no other organizing principle
(often called a paradigm) is needed. When programs become larger, function was adopted
as a way to make programs more comprehensible to their human creators. A procedural
program is divided into functions, and (ideally, at least) each function has a clearly defined
purpose and a clearly defined interface to the other functions in the program.
Dividing a program into functions and modules is one of the cornerstones of struc-
tured programming, the somewhat loosely defined discipline that influenced programming
organization for several decades before the advent of object-oriented programming. As
programs grow ever larger and more complex, even the structured programming approach
begins to show signs of strain. No matter how well the structured programming approach
is implemented, large programs become excessively complex.
What are the reasons for problems with procedural languages? There are two related
problems. First, functions have unrestricted access to global data. Second, unrelated
functions and data, the basis of the procedural paradigm, provide a poor model of the
real world.

• Unrestricted Access: In a procedural program, one written in C for example,


when two or more functions must access the same data—and this is true of the
most important data in a program—then the data must be made global. The
arrangement of local and global variables in a procedural program is shown in
Figure 1.
In a large program, there are many functions and many global data items. The
problem with the procedural paradigm is that this leads to an even larger number
of potential connections between functions and data, as shown in Figure 2. This

5
Chapter 1: Introduction to OOP Object Oriented Programming

Figure 1: Global and local variables.

large number of connections causes problems in several ways. First, it makes a pro-
gram’s structure difficult to conceptualize. Second, it makes the program difficult
to modify. A change made in a global data item may necessitate rewriting all the
functions that access that item. For example, in an inventory management pro-
gram, someone may decide that the product codes for the inventory items should
be changed from 5 digits to 12 digits. This may necessitate a change from a short to
a long data type. Now all the functions that operate on the data must be modified
to deal with a long instead of a short.
When data items are modified in a large program it may not be easy to tell which
functions access the data, and even when you figure this out, modifications to the
functions may cause them to work incorrectly with other global data items. Ev-
erything is related to everything else, so a modification anywhere has far-reaching,
and often unintended, consequences.

Figure 2: Procedural Paradigm.

• Real-World Modeling: The second—and more important—problem with the


procedural paradigm is that its arrangement of separate data and functions does a

6
Chapter 1: Introduction to OOP Object Oriented Programming

poor job of modeling things in the real world. In the physical world we deal with
objects such as people and cars. Such objects aren’t like data and they aren’t like
functions. Complex real-world objects have both attributes and behavior.

– Attributes: Examples of attributes (sometimes called characteristics) are,


for people, eye color and job title; and, for cars, horsepower and number of
doors. As it turns out, attributes in the real world are equivalent to data in
a program: they have a certain specific values, such as blue (for eye color) or
four (for the number of doors).
– Behavior: Behavior is something a real-world object does in response to some
stimulus. If you ask your boss for a raise, she will generally say yes or no. If
you apply the brakes in a car, it will generally stop. Saying something and
stopping are examples of behavior. Behavior is like a function: you call a
function to do something (display the inventory, for example) and it does it.

Note: So neither data nor functions, by themselves, model real-world objects effec-
tively.

1.2.2 The Object-Oriented Approach


The fundamental idea behind object-oriented languages is to combine into a single unit
both data and the functions that operate on that data. Such a unit is called an object.
An object’s functions, called member functions in C++, typically provide the only way to
access its data. If you want to read a data item in an object, you call a member function
in the object. It will access the data and return the value to you. You can’t access the
data directly. The data is hidden, so it is safe from accidental alteration. Data and its
functions are said to be encapsulated into a single entity. Data encapsulation and data
hiding are key terms in the description of object-oriented languages.
If you want to modify the data in an object, you know exactly what functions interact
with it: the member functions in the object. No other functions can access the data. This
simplifies writing, debugging, and maintaining the program.
A C++ program typically consists of a number of objects, which communicate with
each other by calling one another’s member functions. The organization of a C++ pro-
gram is shown in Figure 3.
We should mention that what are called member functions in C++ are called methods
in some other object-oriented (OO) languages (such as Smalltalk, one of the first OO
languages). Also, data items are referred to as attributes or instance variables. Calling
an object’s member function is referred to as sending a message to the object. These
terms are not official C++ terminology, but they are used with increasing frequency,
especially in object-oriented design.

1.3 Object Oriented programming vs procedure oriented pro-


gramming
• Procedural Oriented Programming (POP) uses a top-down approach. The
program is divided into functions and procedures, starting from the main logic and
breaking it into smaller tasks.

7
Chapter 1: Introduction to OOP Object Oriented Programming

Figure 3: The object oriented paradigm.

• Object Oriented Programming (OOP) uses a bottom-up approach. It fo-


cuses on identifying objects first and then building the application by defining
classes and their interactions.
Some key differences between OOP and POP are highlighted in Table 2.

Procedural Programming Object Oriented Program-


(POP) ming (OOP)
Follows top-down approach Follows bottom-up approach
Focuses on procedures or func- Focuses on objects and classes
tions
Data is accessible globally Data is encapsulated within
objects
Code is less modular and Modular code, easier to man-
harder to maintain age and update
Limited code reusability High code reusability

Table 2: Comparison between POP and OOP

8
Chapter 1: Introduction to OOP Object Oriented Programming

1.4 Concepts of object oriented programming


Let’s briefly examine a few of the major elements of object-oriented languages in general,
and C++ in particular.

1.4.1 Objects
When you approach a programming problem in an object-oriented language, you no
longer ask how the problem will be divided into functions, but how it will be divided into
objects. Thinking in terms of objects, rather than functions, has a surprisingly helpful
effect on how easily programs can be designed. This results from the close match between
objects in the programming sense and objects in the real world. What kinds of things
become objects in object-oriented programs? The answer to this is limited only by your
imagination, but here are some typical categories to start you thinking:

• Human entities: Employees, Students, Customers

• Collections of data: An inventory, A personnel file, A dictionary

• User-Define data types: Time, Complex Numbers, Points

The match between programming objects and real-world objects is the happy result of
combining data and functions: The resulting objects offer a revolution in program design.

1.4.2 Classes
In OOP we say that objects are members of classes. Almost all computer languages have
built-in data types. For instance, a data type int, meaning integer, is predefined in C++.
You can declare as many variables of type int as you need in your program. In a similar
way, you can define many objects of the same class, as shown in Figure 4. A class serves
as a plan, or blueprint. It specifies what data and what functions will be included in
objects of that class.
A class is thus a description of a number of similar objects. This fits our non-technical
understanding of the word class. Prince, Sting, and Madonna are members of the rock
musician class. There is no one person called “rock musician,” but specific people with
specific names are members of this class if they possess certain characteristics. An object
is often called an “instance” of a class.

1.4.3 Inheritance
The idea of classes leads to the idea of inheritance. In our daily lives, we use the concept of
classes divided into subclasses. We know that the animal class is divided into mammals,
amphibians, insects, birds, and so on. The vehicle class is divided into cars, trucks, buses,
motorcycles, and so on.
The principle in this sort of division is that each subclass shares common characteris-
tics with the class from which it’s derived. Cars, trucks, buses, and motorcycles all have
wheels and a motor; these are the defining characteristics of vehicles. In addition to the
characteristics shared with other members of the class, each subclass also has its own
particular characteristics: Buses, for instance, have seats for many people, while trucks
have space for hauling heavy loads. This idea is shown in Figure 59. Notice in the figure

9
Chapter 1: Introduction to OOP Object Oriented Programming

Figure 4: Class and it’s Objects.

Figure 5: Inheritance.

10
Chapter 1: Introduction to OOP Object Oriented Programming

that features A and B, which are part of the base class, are common to all the derived
classes, but that each derived class also has features of its own.
In a similar way, an OOP class can become a parent of several subclasses. In C++
the original class is called the base class; other classes can be defined that share its
characteristics, but add their own as well. These are called derived classes.

1.4.4 Reusability
Once a class has been written, created, and debugged, it can be distributed to other
programmers for use in their own programs. This is called reusability. It is similar to
the way a library of functions in a procedural language can be incorporated into different
programs.
However, in OOP, the concept of inheritance provides an important extension to the
idea of reusability. A programmer can take an existing class and, without modifying it,
add additional features and capabilities to it. This is done by deriving a new class from
the existing one. The new class will inherit the capabilities of the old one, but is free to
add new features of its own.
For example, you might have written (or purchased from someone else) a class that
creates a menu system, such as that used in Windows or other Graphic User Interfaces
(GUIs). This class works fine, and you don’t want to change it, but you want to add
the capability to make some menu entries flash on and off. To do this, you simply create
a new class that inherits all the capabilities of the existing one but adds flashing menu
entries. The ease with which existing software can be reused is an important benefit of
OOP.

1.4.5 Creating New Data Types


One of the benefits of objects is that they give the programmer a convenient way to
construct new data types. Suppose you work with two-dimensional positions (such as x
and y coordinates, or latitude and longitude) in your program. You would like to express
operations on these positional values with normal arithmetic operations, such as

position1 = position2 + origin

where the variables position1, position2, and origin each represent a pair of independent
numerical quantities. By creating a class that incorporates these two values, and declaring
position1, position2, and origin to be objects of this class, we can, in effect, create a new
data type. Many features of C++ are intended to facilitate the creation of new data
types in this manner.

1.4.6 Polymorphism and Overloading


Note that the = (equal) and + (plus) operators, used in the position arithmetic shown
above, don’t act the same way they do in operations on built-in types such as int. The
objects position1 and so on are not predefined in C++, but are programmer-defined
objects of class Position. How do the = and + operators know how to operate on
objects? The answer is that we can define new behaviors for these operators. These
operations will be member functions of the Position class. Using operators or functions
in different ways, depending on what they are operating on, is called polymorphism (one
thing with several distinct forms). When an existing operator, such as + or =, is given

11
Chapter 1: Introduction to OOP Object Oriented Programming

the capability to operate on a new data type, it is said to be overloaded. Overloading is


a kind of polymorphism; it is also an important feature of OOP.

1.5 Popular object oriented languages


• C++ – Used in system/software development, game development, and high-performance
applications (e.g., Adobe Photoshop, Unreal Engine).

• Java – Widely used in enterprise applications, Android development, and web


applications (e.g., banking systems, Android Studio apps).

• Python – Commonly used for web development, data science, automation, and
artificial intelligence (e.g., Django, TensorFlow).

• C# – Popular for Windows applications and game development using Unity (e.g.,
enterprise software, .NET applications).

• Ruby – Used in web application development with Rails framework (e.g., GitHub,
Shopify).

• Swift – Primarily used for developing iOS and macOS applications (e.g., iPhone
apps).

• Objective-C – Legacy Apple programming language, still used in older iOS/ma-


cOS apps.

• JavaScript (with classes) – Widely used in modern web development, especially


with frameworks like React, Vue.js, and Node.js.

1.6 Advantages of OOP


Object-Oriented Programming (OOP) offers several advantages that make it a preferred
paradigm for large-scale software development. One of the most significant benefits is
reusability. Classes and objects can be reused across different programs, reducing du-
plication and development effort. Another core concept is inheritance, which allows a
new class to acquire the properties and behaviors of an existing class. This supports
hierarchical classification and simplifies code extension and maintenance.
Polymorphism enhances flexibility by allowing the same operation to behave differ-
ently on different classes, making code more generic and extensible. OOP also improves
modularity, as the program is divided into smaller, self-contained units (objects), which
makes the system easier to design, test, and debug. Additionally, encapsulation hides the
internal state of objects and exposes only necessary parts, thereby ensuring data security
and integrity.

1.7 Disadvantages of OOP


However, OOP is not without its drawbacks. One of the primary disadvantages is the
added complexity. Concepts like inheritance, polymorphism, and encapsulation can be
challenging for beginners to learn and apply effectively. OOP can also introduce addi-
tional overhead, both in terms of performance and memory usage, which may not be ideal
for low-resource environments. Furthermore, OOP-based solutions often result in larger

12
Chapter 1: Introduction to OOP Object Oriented Programming

codebases, which could be considered inefficient for simple tasks. Lastly, for small-scale
or procedural problems, using OOP might be unnecessary and lead to over-engineered
solutions.

13
Chapter 2: Basics of c++ Programming Object Oriented Programming

Chapter 2: Basics of c++ Programming


2.1 C++ Program structure
The structure of the program written in C++ is shown in below:

Documentation Section
Linking Section
Class Declaration/definition
Member function definition
Main Function

Table 3: Structure of c++ program

• Documentation Section: This section is used to document the logic of the pro-
gram that the programmer going to code, Whatever written in the documentation
section is the comment and is not compiled by the compiler.
Listing 1: Comments in C++
// This is a C ++ program to find the Area of the circle

Note: It also supports C Style comments like /*........*/

• Linking Section:

– Header Files: A program includes various programming elements like built-in


functions, classes, keywords, constants, operators, etc. that are already de-
fined in the standard C++ library. In order to use such pre-defined elements
in a program, an appropriate header must be included in the program. Stan-
dard headers are specified in a program through the preprocessor directive
#include.
Listing 2: Header Files in C++
# include < iostream >

When the compiler processes the instruction #include <iostream>, it in-


cludes the contents of the stream in the program. This enables the program-
mer to use standard input, output, and error facilities that are provided only
through the standard streams defined in <iostream>. These standard streams
process data as a stream of characters, that is, data is read and displayed in a
continuous flow.
– Namespaces: A namespace permits grouping of various entities like classes,
objects, functions, and various C++ tokens, etc. under a single name.
Listing 3: Namespace
using namespace std ;

In the above snippets, namespace std contains declarations for cout, cin, endl,
etc. statements.

14
Chapter 2: Basics of c++ Programming Object Oriented Programming

• Class Declaration/definition Section: Here, in this section, classes used in the


program are declared and/or defined. Body of class is enclosed by curly brackets
and ends with a semicolon. Class consists of attributes and functions which are the
members of that class.
Listing 4: Declaration Section
class MyClass {
public :
void display () ;
};

• Member Function Definition Section: Member functions can be defined inside


or outside the class. If the member function is defined outside the class, we need
to use class name to which the function belongs and scope resolution operator(::)
before function name.
Listing 5: Member Function Definition
void className :: input ()
{
cout <<" Enter values of a and b : " ;
cin >> a >> b ;
}

• Main Function: The main function tells the compiler where to start the execution
of the program.
Listing 6: Main Function
int main ()
{
printMax () ;
return 0;
}

2.2 Character set and tokens


The character set refers to all the characters that are valid in a C++ program.
• Letters: A-Z, a-z
• Digits: 0-9
• Special Characters: ~ ! # % ^ & * ( ) - + = { } [ ] | \ : ; " ’ <
> , . ? /
• Whitespace Characters: Space ( ), Tab (\t), Newline (\n), Carriage return (\r)
Tokens are the smallest individual units in a C++ program. The tokens in c++ are:
• Keywords: Reserved words with special meaning. Listed in the Table below:
• Identifiers: Names used for variables, functions, arrays, classes, etc. Must start
with a letter or underscore, followed by letters, digits, or underscores. Case-sensitive
and cannot be a keyword.

15
Chapter 2: Basics of c++ Programming Object Oriented Programming

• Constants / Literals: Fixed values like:

– Integer constants: 10, -55


– Real constants: 3.14, -0.001
– Character constants: ’a’, ’9’
– String literals: "Hello", "123"

• Operators: Symbols to perform operations:

– Arithmetic: +, -, *, /, %
– Relational: ==, !=, <, >, <=, >=
– Logical: &&, ||, !
– Assignment: =, +=, -=, *=, /=

• Separators / Punctuation: ;, ,, (), {}, [], :, #

• Comments:

– Single-line: // This is a comment


– Multi-line: /* This is a comment */

C++ Keywords:

alignas alignof and and eq


asm auto bitand bitor
bool break case catch
char char8 t char16 t char32 t
class compl concept const
consteval constexpr constinit const cast
continue co await co return co yield
decltype default delete do
double dynamic cast else enum
explicit export extern false
float for friend goto
if inline int long
mutable namespace new noexcept
not not eq nullptr operator
or or eq private protected
public register reinterpret cast requires
return short signed sizeof
static static assert static cast struct
switch template this thread local
throw true try typedef
typeid typename union unsigned
using virtual void volatile
wchar t while xor xor eq

16
Chapter 2: Basics of c++ Programming Object Oriented Programming

2.3 Variable declaration and expression


Variables can be declared in C++ as:
data type variable name;
data type variable name1,variable name2,...;
Example:
Listing 7: Integer Variables
int var1 , var2 ;

The statement define two integer variables, var1 and var2. The keyword int signals the
type of variable. These statements, which are called declarations, must terminate with
a semicolon, like other program statements. You must declare a variable before using it.
However, you can place variable declarations anywhere in a program. It’s not necessary to
declare variables before the first executable statement (as was necessary in C). However,
it’s probably more readable if commonly-used variables are located at the beginning of
the program.
The combination of operands and operators is known as expression. For example in
the expression: x = a + b;. x,a,b are operands and +,= are operator.

Cin and Cout in C++:


Listing 8: Use of Cout
cout << " Every age has a language of its own \ n " ;

The above statement causes the phrase in quotation marks to be displayed on the screen.
The identifier cout (pronounced “C out”) is actually an object. It is predefined in C++
to correspond to the standard output stream. A stream is an abstraction that refers to
a flow of data. The operator << is called the insertion or put to operator. It directs the
contents of the variable on its right to the object on its left. In above statement it directs
the string constant “Every age has a language of its own\n” to cout, which sends it to
the display.

Figure 6: Output with Cout.

Listing 9: Use of Cin


int a ;
cin > > a ;

The above statement causes the program to wait for the user to type in a number.The
resulting number is placed in the variable a. The keyword cin (pronounced “C in”) is

17
Chapter 2: Basics of c++ Programming Object Oriented Programming

an object, predefined in C++ to correspond to the standard input stream. This stream
represents data coming from the keyboard (unless it has been redirected). The >> is the
extraction or get from operator. It takes the value from the stream object on its left and
places it in the variable on its right.

Figure 7: Input with Cin.

Write a Program in C++ to input temperature in Fahrenheit and convert it into


Celsius:
Listing 10: Example Program
// fahren . cpp
// demonstrates cin , newline
# include < iostream >
using namespace std ;
int main ()
{
int ftemp ; // for temperature in fahrenheit
cout << " Enter temperature in fahrenheit : " ;
cin >> ftemp ;
int ctemp = ( ftemp -32) * 5 / 9;
cout << " Equivalent in Celsius is : " << ctemp << endl ;
return 0;
}

The endl Manipulator: endl causes a linefeed to be inserted into the stream,
so that subsequent text is displayed on the next line. It has the same effect as sending
the ‘\n’ character, but is somewhat clearer. Manipulators are instructions to the output
stream that modify the output in various ways; we’ll see more of them as we go along.
Strictly speaking, endl (unlike ‘\n’) also causes the output buffer to be flushed, but this
happens invisibly so for most purposes the two are equivalent.
Cascading << and >>: The extraction operator >> can be cascaded with cin allowing
the user to enter a series of values. We can do same for the insertion operator as well.

2.4 Data types


The data types used in C++ is shown in Figure 8.
C++ provides several built-in (fundamental) data types used to declare variables for
different kinds of data. These types form the basis of all operations in a C++ program.

• Integer: Integer variables represent integer numbers like 1, 30,000, and –27.
Integer variables exist in several sizes, but the most commonly used is type int.
The amount of memory occupied by the integer types is system dependent. On
a 32-bit system such as Windows, an int occupies 4 bytes (which is 32 bits) of

18
Chapter 2: Basics of c++ Programming Object Oriented Programming

Figure 8: Data Types in C++

Table 4: Fundamental Data Types in C++ (Typical 32-bit System)

Data Type Size (Bytes) Range


int 4 -2,147,483,648 to 2,147,483,647
char 1 -128 to 127 or 0 to 255 (unsigned)
float 4 3.4e±38 (6 digits precision)
double 8 1.7e±308 (15 digits precision)
bool 1 true / false (1 / 0)

memory. This allows an int to hold numbers in the range from –2,147,483,648
to 2,147,483,647. C++ allows the use of modifiers to alter the size or sign of an
integer type. Type long always occupies four bytes, which is the same as type int
on 32-bit Windows systems. On all systems type short occupies two bytes, giving
it a range of –32,768 to 32,767. These are shown in Table 5:

Table 5: Modified Integer Types

Type Size (Bytes) Range


short int / short 2 -32,768 to 32,767
unsigned short int 2 0 to 65,535
long int / long 4 -2,147,483,648 to 2,147,483,647
unsigned long int 4 0 to 4,294,967,295
unsigned int 4 0 to 4,294,967,295

• Character Variables: Type char stores integers that range in value from –128 to
127. Variables of this type occupy only 1 byte (eight bits) of memory. As you may
already know, the ASCII character set is a way of representing characters such as ‘a’,
‘B’, ‘$’, ‘3’, and so on, as numbers. These numbers range from 0 to 127. Standard
C++ provides a larger character type called wchar t to handle foreign languages.
This is important if you’re writing programs for international distribution.

19
Chapter 2: Basics of c++ Programming Object Oriented Programming

• Floating Point Types: Floating-point variables represent numbers with a deci-


mal place—like 3.1415927, 0.0000625, and –10.2. There are three kinds of floating-
point variables in C++: type float, type double, and type long double.
float PI = 3.14159F;
The number 3.14159F in PI is an example of a floating-point constant. The decimal
point signals that it is a floating-point constant, and not an integer, and the F
specifies that it’s type float, rather than double or long double. The number is
written in normal decimal notation. You don’t need a suffix letter with constants
of type double; it’s the default. With type long double, use the letter L.

Table 6: Floating Point Data Types in C++

Type Size (Bytes) Precision Approximate Range


float 4 7 decimal digits 3.4 × 10−38 to 3.4 × 1038
double 8 15 decimal digits 1.7 × 10−308 to 1.7 × 10308
long double (platform dependent)

Notes:

– Use suffix f or F for float literals (e.g., 3.14f).


– Floating point literals without suffix are of type double by default.

• Bool: Variables of type bool can have only two possible values: true and false.
In theory a bool type requires only one bit (not byte) of storage, but in practice
compilers often store them as bytes because a byte can be quickly accessed, while
an individual bit must be extracted from a byte, which requires additional time.

Input and Output:

• The setw Manipulator: We have already seen the use of the endl manipulator.
Now, let us explore another manipulator: setw, which changes the field width of
output. Each value displayed by cout can be thought of as occupying a field: an
imaginary box with a certain width. By default, this width is just enough to hold
the value. For example: The integer 567 occupies a field three characters wide.
The string "pajamas" occupies a field seven characters wide. However, this default
formatting may not always be visually ideal. Consider the following program:
Listing 11: Demonstrating Need for setw
# include < iostream >
using namespace std ;

int main () {
int pop1 = 2425785 , pop2 = 47 , pop3 = 9761;

cout << " LOCATION " << " POP . " << endl
<< " Portcity " << pop1 << endl
<< " Hightown " << pop2 << endl
<< " Lowville " << pop3 << endl ;

return 0;
}

20
Chapter 2: Basics of c++ Programming Object Oriented Programming

Sample Output:

LOCATION POP.
Portcity 2425785
Hightown 47
Lowville 9761

As you can see, this format makes it hard to compare the population numbers.
Ideally, we want the population values to align to the right for better readability.
Furthermore, inserting spaces manually to separate city names and numbers is
inconvenient.
In such cases, the setw manipulator can be used to specify a consistent field width
for numerical output, improving alignment and presentation. To improve the read-
ability of output and ensure proper alignment, C++ provides the setw manipulator
(from the iomanip header). The setw(n) function prints the following item in a
field at least n characters wide, right-justified by default.

Here is a revised version of the earlier program that demonstrates the use of setw:
Listing 12: Demonstration of setw Manipulator
# include < iostream >
# include < iomanip > // for setw
using namespace std ;

int main () {
int pop1 = 2425785 , pop2 = 47 , pop3 = 9761;

cout << setw (8) << " LOCATION " << setw (12) << " POPULATION " <<
endl
<< setw (8) << " Portcity " << setw (12) << pop1 << endl
<< setw (8) << " Hightown " << setw (12) << pop2 << endl
<< setw (8) << " Lowville " << setw (12) << pop3 << endl ;

return 0;
}

Sample Output:

LOCATION POPULATION
Portcity 2425785
Hightown 47
Lowville 9761

The setw manipulator improves the visual alignment of the output and avoids the
need to manually adjust spacing.

21
Chapter 2: Basics of c++ Programming Object Oriented Programming

Figure 9: Setw Manipulator

Listing 13: Demonstration of setw(), left, and right


# include < iostream >
# include < iomanip >
using namespace std ;

int main () {
string name1 = " Alice " ;
string name2 = " Bob " ;
int score1 = 95;
int score2 = 87;

cout << left << setw (10) << " Name " << right << setw (6) << "
Score " << endl ;
cout << left << setw (10) << name1 << right << setw (6) << score1
<< endl ;
cout << left << setw (10) << name2 << right << setw (6) << score2
<< endl ;

return 0;
}

Sample Output:

Name Score
Alice 95
Bob 87

– setw(10) sets a field width of 10 characters for the name column.


– left aligns the name text to the left within the 10-character field.
– setw(6) sets a field width of 6 characters for the score column.
– right aligns the numeric score to the right within the 6-character field.
– The use of left and right manipulators improves readability and creates a
clean, table-like format in the output.

Note that setw() only applies to the next output item, and must be used repeatedly
for each value if consistent formatting is desired.

22
Chapter 2: Basics of c++ Programming Object Oriented Programming

• The Setfill Manipulator The setfill manipulator (defined in the iomanip


header) is used to specify a fill character for fields formatted using setw. By de-
fault, unused space in a field is filled with blanks. The setfill(ch) manipulator
replaces these blanks with the specified character ch.

Listing 14: Demonstration of setfill


# include < iostream >
# include < iomanip > // for setw , setfill
using namespace std ;
int main () {
cout << setfill ( '* ') << setw (10) << 123 << endl ;
cout << setfill ( ' - ') << setw (10) << " Hello " << endl ;
return 0;
}

Sample Output:

*******123
-----Hello

Note: This affects only the field created by setw.

• The Setprecision Manipulator: The setprecision manipulator (from the


iomanip header) is used to control the number of significant digits or decimal places
displayed for floating-point numbers.

Listing 15: Demonstration of setprecision


# include < iostream >
# include < iomanip > // for setw , setfill
using namespace std ;

int main () {
float a = 0.00123 f ;

cout << a << endl ;


cout << fixed << setprecision (4) << a << endl ;
cout << scientific << setprecision (4) << a << endl ;

return 0;
}

Sample Output:

0.00123
0.0012
1.2300e-03

The code in Listing 15 demonstrates the usage of the setprecision manipulator in


C++ for controlling the number of digits displayed in floating-point numbers. The
output varies depending on whether the number is displayed in the default format,
fixed-point notation, or scientific notation.

23
Chapter 2: Basics of c++ Programming Object Oriented Programming

– The first cout statement simply outputs the value of the float variable a. By
default, C++ prints floating-point numbers using the shortest representation
that accurately reflects the value, which is 0.00123 in this case.
– The second cout uses the fixed manipulator along with setprecision(4).
In fixed-point notation, setprecision controls the number of digits displayed
after the decimal point. Thus, the output becomes 0.0012, rounding the value
to four decimal places.
– The third cout uses the scientific manipulator along with setprecision(4).
In scientific notation, setprecision again sets the number of digits after the
decimal point. Therefore, the output is displayed as 1.2300e-03, which is the
scientific representation of 0.00123 rounded to four digits after the decimal
point.

This example clearly illustrates how the formatting manipulators fixed and scientific,
when used with setprecision, can control the precision and format of floating-
point output in C++. Note: To revert back to normal (default) formatting,
use cout.unsetf(scientific);

Listing 16: Demonstration of setprecision without fixed or scientific


# include < iostream >
# include < iomanip >
using namespace std ;

int main () {
float a = 123.456 f ;
float b = 0.00123456 f ;

cout << setprecision (3) << " a = " << a << " , b = " << b << endl ;
cout << setprecision (4) << " a = " << a << " , b = " << b << endl ;
cout << setprecision (6) << " a = " << a << " , b = " << b << endl ;

return 0;
}

Sample Output:

a = 123, b = 0.0012
a = 123.5, b = 0.001235
a = 123.456, b = 0.00123456

The code in Listing 16 demonstrates the behavior of the setprecision manipulator when
used without the fixed or scientific manipulators. In this case, setprecision(n)
controls the total number of significant digits displayed in the output.

• With setprecision(3):

– a = 123.456 is displayed as 123, keeping only the first three significant digits
and rounding the rest.
– b = 0.00123456 is shown as 0.00123, rounded to three significant digits.

• With setprecision(4):

24
Chapter 2: Basics of c++ Programming Object Oriented Programming

– a is displayed as 123.5, rounding to four significant digits.


– b becomes 0.001235, preserving more digits than before.

• With setprecision(6):

– Both a and b are shown in full, as they originally have six significant digits.
The output is 123.456 and 0.00123456, respectively.

This example highlights that when fixed or scientific is not specified, the C++ output
stream chooses between fixed-point and scientific notation automatically based on the
value and the number of significant digits requested.
Q:
Write a C++ program to display the following table using the setw() and left manip-
ulators from the <iomanip> library to align the columns properly[Note: Can use left
manipulator.]:

Name Age City


Ram 23 Bhaktapur
Hari 30 Kathmandu

2.5 Type conversion and casting


C++, like C, is more forgiving than some languages in the way it treats expressions
involving several different data types. As an example, consider the following program:
Listing 17: Shows mixed expressions
# include < iostream >
using namespace std ;

int main ()
{
int count = 7;
float avgWeight = 155.5 F ;
double totalWeight = count * avgWeight ;

cout << " totalWeight = " << totalWeight << endl ;


return 0;
}

Here, a variable of type int is multiplied by a variable of type float to yield a result
of type double. This program compiles without error; the compiler considers it normal
that you want to multiply (or perform any other arithmetic operation on) numbers of
different types.
C++ and C, however, assume that you must have a good reason for doing what you’re
doing, and they help carry out your intentions. This is one reason for the popularity of
C++ and C: they give you more freedom. Of course, with more freedom, there’s also
more opportunity for you to make a mistake.

2.5.1 Automatic Conversions


Let’s consider what happens when the compiler confronts such mixed-type expressions
as the above program 15. Types are considered “higher” or “lower,” based roughly on

25
Chapter 2: Basics of c++ Programming Object Oriented Programming

Figure 10: Type Conversion

the order shown in Table 7. The process and promotion of data types is shown in Figure
10. When mixed-type expressions are encountered, the lower-type operand is converted
to the higher-type operand before computation. For instance, in above example:

• count (int) is promoted to float before multiplication.

• The result (float) is promoted to double for assignment to totalWeight.

These conversions are implicit and automatic, but they can sometimes cause unexpected
behavior or loss of precision.

Table 7: Hierarchy of C++ Data Types for Type Promotion

Order of Data Types (Highest to Lowest)


long double
double
float
long
int
short
char

2.5.2 Casts
Casts are also called type casts. What are casts for? Sometimes a programmer needs to
convert a value from one type to another in a situation where the compiler will not do it
automatically or without complaining. There are several kinds of casts in Standard C++:

26
Chapter 2: Basics of c++ Programming Object Oriented Programming

static casts, dynamic casts, reinterpret casts, and const casts. Here we’ll be concerned
only with static casts.
Listing 18: Using cast to get a floating-point result from integer division
# include < iostream >
using namespace std ;

int main () {
int a = 5;
int b = 2;

// Without cast - integer division


float result1 = a / b ;
cout << " Without cast : " << result1 << endl ; // Outputs 2

// With cast - floating point division


float result2 = static_cast < float >( a ) / b ;
cout << " With cast : " << result2 << endl ; // Outputs 2.5

return 0;
}

static cast is used in C++ to explicitly convert a variable from one data type to
another. It is a safer and more visible alternative to traditional C-style casting.
• Syntax: static cast<new type>(expression);
• It creates a temporary variable of the specified new type, initialized with the value
of expression.
• Useful when implicit conversion might result in loss of data or when precision is
required (e.g., converting int to float to avoid integer division).
Example:
float result = static_cast<float>(5) / 2; // Outputs 2.5
Without static cast, 5 / 2 would perform integer division, yielding 2.
Question: Write a C++ program that takes an integer input between 65 and 90 (in-
clusive), and prints the corresponding uppercase alphabet character using static cast.
Sample Output :
Input: 65
Output: A

2.6 User defined constant const


Consider the statement:
Listing 19: Using const in C++
const float PI = 3.14159 F ;
const int n ;

The keyword const (short for constant) precedes the data type of a variable. It specifies
that the value of the variable will not change throughout the program. Any attempt
to modify a variable defined with this qualifier will result in a compiler error. The line
number 2 will throw a compilition error error as constant is not initialized.

27
Chapter 2: Basics of c++ Programming Object Oriented Programming

Figure 11: Arithmetic assignment operator.

2.7 Operators
• Arithmetic Operators: C++ uses the four normal arithmetic operators +, -, *,
and / for addition, subtraction, multiplication, and division. These operators work
on all the data types, both integer and floating-point. There is a fifth arithmetic
operator that works only with integer variables (types char, short, int, and long).
It is called the remainder operator, and is represented by the percent symbol (%).
This operator is also known as the modulus operator. It finds the remainder
when one number is divided by another.

• Arithmetic Assignment Operators: C++ offers several ways to shorten and


clarify your code. One of these is the arithmetic assignment operator. This
operator helps to give C++ listings their distinctive appearance. The following
kind of statement is common in most languages:

total = total + item; // adds item to total

In this situation you add something to an existing value (or you perform some other
arithmetic operation on it). But the syntax of this statement offends those for
whom brevity is important, because the name total appears twice. So C++ offers
a condensed approach: the arithmetic assignment operator, which combines
an arithmetic operator and an assignment operator. Here’s a statement that has
exactly the same effect as the preceding one:

total += item; // adds item to total

There are arithmetic assignment operators corresponding to all the arithmetic op-
erations: +=, -=, *=, /=, and %= (and some other operators as well).

28
Chapter 2: Basics of c++ Programming Object Oriented Programming

• Increment Operators: Here’s an even more specialized operator. You often need
to add 1 to the value of an existing variable. You can do this the “normal” way:

count = count + 1; % adds 1 to count

Or you can use an arithmetic assignment operator:

count += 1; % adds 1 to count

But there’s an even more condensed approach:

++count; % adds 1 to count

The ++ operator increments (adds 1 to) its argument.


Prefix and Postfix: The increment operator can be used in two ways: as a
prefix, meaning that the operator precedes the variable; and as a postfix, meaning
that the operator follows the variable. What’s the difference? Often a variable
is incremented within a statement that performs some other operation on it. For
example

totalWeight = avgWeight * ++count;

The question here is this: Is the multiplication performed before or after count
is incremented? In this case count is incremented first. How do we know that?
Because prefix notation is used: ++count. If we had used postfix notation, count++,
the multiplication would have been performed first, then count would have been
incremented. This is shown in Figure 12.
The Decrement Operator: The decrement operator, --, behaves very much
like the increment operator, except that it subtracts 1 from its operand. It too can
be used in both prefix and postfix forms.
• Relational Operators: A relational operator compares two values. The values
can be any built-in C++ data type, such as char, int, and float, or—as we’ll see
later—they can be user-defined classes. The comparison involves such relationships
as equal to, less than, and greater than. The result of the comparison is true or
false; for example, either two values are equal (true), or they’re not (false).
Here’s the complete list of C++ relational operators:
Operator Meaning
> Greater than
< Less than
== Equal to
!= Not equal to
>= Greater than or equal to
<= Less than or equal to
• The Conditional Operator: This operator consists of two symbols, which oper-
ate on three operands. It’s the only such operator in C++; other operators operate
on one or two operands. Here’s the equivalent of the same program fragment, using
a conditional operator:

29
Chapter 2: Basics of c++ Programming Object Oriented Programming

Figure 12: The increment Operator

min = (alpha < beta) ? alpha : beta;

The part of this statement to the right of the equal sign is called the conditional
expression:

(alpha < beta) ? alpha : beta // conditional expression

Figure 13 shows the syntax of conditional operator and 14 shows the execution of
conditional operator.

• Logical Operators: Let’s examine a third family of operators, called logical


operators. These operators allow you to logically combine Boolean variables (that
is, variables of type bool, with true or false values).

Figure 13: Conditional Operator

30
Chapter 2: Basics of c++ Programming Object Oriented Programming

Figure 14: Execution of Conditional Operator.

Table 8: Logical Operators

Symbol Meaning Example


&& Logical AND (a > 0 && b > 0)
|| Logical OR (a > 0 || b > 0)
! Logical NOT !(a > 0)

• Precedence: Let’s summarize the precedence situation for the operators we’ve
seen so far. The operators higher on the list have higher precedence than those
lower down. This is show in Table 9.
Table 9: Operator Types, Symbols, and Their Precedence

Operator Type Operators Precedence


Unary !, ++, --, +, - Highest
Arithmetic (Multiplicative) *, /, %
Arithmetic (Additive) +, -
Relational (Inequality) <, >, <=, >=
Relational (Equality) ==, !=
Logical (And) &&
Logical (Or) ||
Conditional ?:
Assignment =, +=, -=, *=, /=, %= Lowest

2.8 Reference variables


In C++, a reference variable is copy of variable or an alias(alternate name) for another
variable. It does not occupy its own memory but simply acts as another name for an
existing variable.

31
Chapter 2: Basics of c++ Programming Object Oriented Programming

Figure 15: Reference Variable

Syntax
datatype &referenceName = originalVariable;

Example
int a = 10;
int &b = a;

b = 20; // This also changes the value of 'a' to 20

Key Characteristics
• A reference must be initialized when declared.
• Once a reference is initialized to a variable, it cannot be changed to refer to another
variable.
• Modifying the reference modifies the original variable.

2.9 Conditions and looping


2.9.1 Conditions
Programs needs to make these one-time decisions. In a program a decision causes a
onetime jump to a different part of the program, depending on the value of an expres-
sion. Decisions can be made in C++ in several ways. The most important is with the
if...else statement, which chooses between two alternatives. This statement can be
used without the else, as a simple if statement. Another decision statement, switch,
creates branches for multiple alternative sections of code, depending on the value of a
single variable. Finally, the conditional operator is used in specialized situations.
Blocks and Variable Visibility: The condition/loop body, which consists of braces
delimiting several statements, is called a block of code. One important aspect of a block
is that a variable defined inside the block is not visible outside it. Visible means that
program statements can access or “see” the variable.

32
Chapter 2: Basics of c++ Programming Object Oriented Programming

Listing 20: Scope example with block


# include < iostream >
using namespace std ;

int main () {
int a = 10;
{
int b = 20;
}
cout << b ; // Error : 'b ' is out of scope here
return 0;
}

• The if Statement: The if statement is the simplest of the decision statements.


Our next program provides an example.
Listing 21: IF statement
# include < iostream >
using namespace std ;

int main ()
{
int x ;
cout << " Enter a number : " ;
cin >> x ;
if ( x > 100)
cout << " That number is greater than 100\ n " ;
return 0;
}

The if keyword is followed by a test expression in parentheses. The syntax of the


if statement is shown in Figure 16 and execution is shown in Figure 17.

33
Chapter 2: Basics of c++ Programming Object Oriented Programming

Figure 16: Syntax of IF statement.

Figure 17: Execution of IF statement.

You can nest ifs inside loops, loops inside ifs, ifs inside ifs, and so on. Here’s
an example, PRIME, that nests an if.
Listing 22: Prime Number – nested if inside loop
# include < iostream >
using namespace std ;
# include < cstdlib > // for exit ()

34
Chapter 2: Basics of c++ Programming Object Oriented Programming

int main ()
{
unsigned long n , j ;
cout << " Enter a number : " ;
cin >> n ; // get number to test

for ( j = 2; j <= n / 2; j ++) // divide by every integer from 2


on up
if ( n % j == 0) // if remainder is 0 , it 's divisible by j
{
cout << " It 's not prime ; divisible by " << j << endl ;
exit (0) ; // exit from the program
}

cout << " It 's prime \ n " ;


return 0;
}

• The if...else Statement: The if statement lets you do something if a condition


is true. If it isn’t true, nothing happens. But suppose we want to do one thing if a
condition is true, and do something else if it’s false. That’s where the if...else
statement comes in. It consists of an if statement, followed by a statement or
block of statements, followed by the keyword else, followed by another statement
or block of statements. The syntax is shown in Figure 18

35
Chapter 2: Basics of c++ Programming Object Oriented Programming

Figure 18: Syntax of IF...ELSE

Listing 23: if...else statement


int main ()
{
int x ;
cout << " \ nEnter a number : " ;
cin >> x ;
if ( x > 100)
cout << " That number is greater than 100\ n " ;
else
cout << " That number is not greater than 100\ n " ;
return 0;
}

The operation of if else is shown in Figure 19.

36
Chapter 2: Basics of c++ Programming Object Oriented Programming

Figure 19: Operation of IF...ELSE

• Nested IF ELSE: In C++, an if...else statement can be nested inside another


if...else statement. This is useful when you want to test multiple conditions in
a structured way.
Listing 24: Nested if...else example
# include < iostream >
using namespace std ;

int main ()
{
int num ;
cout << " Enter a number : " ;
cin >> num ;

if ( num >= 0)
{
if ( num == 0)
cout << " The number is zero .\ n " ;
else
cout << " The number is positive .\ n " ;
}
else
{
cout << " The number is negative .\ n " ;
}

return 0;
}

• ELSE IF Construction: The else if ladder is used to check multiple conditions


one after another. If one condition is true, the corresponding block runs and the
rest are skipped.

37
Chapter 2: Basics of c++ Programming Object Oriented Programming

Listing 25: else if ladder example


# include < iostream >
using namespace std ;

int main ()
{
int marks ;
cout << " Enter your marks : " ;
cin >> marks ;

if ( marks >= 90)


cout << " Grade : A \ n " ;
else if ( marks >= 75)
cout << " Grade : B \ n " ;
else if ( marks >= 60)
cout << " Grade : C \ n " ;
else
cout << " Grade : D \ n " ;

return 0;
}

• Switch: If you have a large decision tree, and all the decisions depend on the
value of the same variable, you will probably want to consider a switch statement
instead of a ladder of if...else or else if constructions.
The switch statement provides a cleaner and more readable way to handle such
cases, especially when comparing the same variable against multiple constant values.
The Syntax is shown in Figure 20 and execution is shown in Figure 21.

38
Chapter 2: Basics of c++ Programming Object Oriented Programming

Figure 20: Switch Syntax

Figure 21: Switch Execution

39
Chapter 2: Basics of c++ Programming Object Oriented Programming

Listing 26: Calculator using switch statement


# include < iostream >
using namespace std ;

int main ()
{
double num1 , num2 ;
char op ;

cout << " Enter first number : " ;


cin >> num1 ;

cout << " Enter an operator (+ , -, * , /) : " ;


cin >> op ;

cout << " Enter second number : " ;


cin >> num2 ;

switch ( op )
{
case '+ ':
cout << " Result : " << num1 + num2 << endl ;
break ;
case ' - ':
cout << " Result : " << num1 - num2 << endl ;
break ;
case '* ':
cout << " Result : " << num1 * num2 << endl ;
break ;
case '/ ':
if ( num2 != 0)
cout << " Result : " << num1 / num2 << endl ;
else
cout << " Error : Division by zero is not allowed .\ n "
;
break ;
default :
cout << " Invalid operator !\ n " ;
}

return 0;
}

2.9.2 Loops:
Loops cause a section of your program to be repeated a certain number of times. The
repetition continues while a condition is true. When the condition becomes false, the
loop ends and control passes to the statements following the loop.
There are three kinds of loops in C++ for, while and do...while loop.

• for loop: The for loop is (for many people, anyway) the easiest C++ loop to
understand. All its loop-control elements are gathered in one place, while in the
other loop constructions they are scattered about the program, which can make it
harder to unravel how these loops work.

40
Chapter 2: Basics of c++ Programming Object Oriented Programming

The for loop executes a section of code a fixed number of times. It’s usually
(although not always) used when you know, before entering the loop, how many
times you want to execute the code.
Listing 27: Using the for loop
# include < iostream >
using namespace std ;

int main ()
{
int j ; // define a loop variable
for ( j = 0; j < 15; j ++) // loop from 0 to 14
cout << j * j << " " ; // displaying the square of j

cout << endl ;


return 0;
}

The for statement controls the loop. It consists of the keyword for, followed by
parentheses that contain three expressions separated by semicolons:

for(j = 0; j < 15; j++)

These three expressions are:

– Initialization Expression: j = 0 — sets the starting value of the loop vari-


able.
– Test Expression: j < 15 — checks whether the loop should continue.
– Increment Expression: j++ — updates the loop variable after each itera-
tion.

These three expressions usually (but not always) involve the same variable, which
we call the loop variable. The body of the loop is the code to be executed each
time through the loop. The operation of for loop is shown in Figure 23.

41
Chapter 2: Basics of c++ Programming Object Oriented Programming

Figure 22: Syntax of for loop.

Figure 23: Operation of for loop

Variables Defined in for Statements:


The loop variable j is defined inside the for statement:

for(int j = numb; j > 0; j--)

This is a common construction in C++, and in most cases it’s the best approach
to loop variables. It defines the variable as closely as possible to its point of use in
the listing.

42
Chapter 2: Basics of c++ Programming Object Oriented Programming

Variables defined in the loop statement this way are visible in the loop body only.

• while loop: The for loop does something a fixed number of times. What happens
if you don’t know how many times you want to do something before you start the
loop?
In this case, a different kind of loop may be used: the while loop.
Listing 28: Using the while loop
# include < iostream >
using namespace std ;

int main ()
{
int n = 99; // make sure n isn 't initialized to 0

while ( n != 0) // loop until n is 0


cin >> n ; // read a number into n

cout << endl ;


return 0;
}

The while loop looks like a simplified version of the for loop. It contains a test
expression but no initialization or increment expressions. The syntax of while loop
is shown in Figure 24 and operation is shown in 25.

Figure 24: Syntax of while loop

43
Chapter 2: Basics of c++ Programming Object Oriented Programming

Figure 25: Operation of while loop

• do...while loop: n a while loop, the test expression is evaluated at the beginning
of the loop. If the test expression is false when the loop is entered, the loop body
won’t be executed at all.
In some situations, this is what you want. But sometimes you want to guarantee
that the loop body is executed at least once, no matter what the initial state of the
test expression.
When this is the case, you should use the do loop, which places the test expression
at the end of the loop.
Listing 29: Using the do...while loop
# include < iostream >
using namespace std ;

int main ()
{
long dividend , divisor ;
char ch ;

do // start of do loop
{
// do some processing
cout << " Enter dividend : " ;
cin >> dividend ;

cout << " Enter divisor : " ;


cin >> divisor ;

cout << " Quotient is " << dividend / divisor ;


cout << " , remainder is " << dividend % divisor ;

cout << " \ nDo another ? ( y / n ) : " ; // do it again ?


cin >> ch ;
}
while ( ch != 'n ') ; // loop condition

return 0;

44
Chapter 2: Basics of c++ Programming Object Oriented Programming

Most of this program resides within the do loop. First, the keyword do marks the
beginning of the loop. Then, as with the other loops, braces delimit the body of
the loop.
Finally, a while statement provides the test expression and terminates the loop.
This while statement looks much like the one in a while loop, except for its position
at the end of the loop and the fact that it ends with a semicolon (which is easy to
forget!).
The syntax of the do loop is shown in Figure 26 and operation is shown in 27.

Figure 26: Syntax of do while loop

Figure 27: Operation of do while loop

45
Chapter 2: Basics of c++ Programming Object Oriented Programming

The break and Continue statement:


The break statement causes an exit from a loop, just as it does from a switch state-
ment. The next statement after the break is executed is the statement following the loop.
Figure 28. shows the operation of the break statement.

Figure 28: Operation of break

Sometimes, however, you want to go back to the top of the loop when something
unexpected happens.
Executing continue has this effect. (Strictly speaking, the continue takes you to
the closing brace of the loop body, from which you may jump back to the top.)
Figure 29 shows the operation of continue.

Figure 29: Operation of continue

Listing 30: Examples of break and continue in loops


# include < iostream >
using namespace std ;

int main () {
for ( int i = 1; i <= 10; i ++) {
if ( i == 5) {

46
Chapter 2: Basics of c++ Programming Object Oriented Programming

cout << " Skipping 5\ n " ;


continue ; // Skip the rest of this iteration when i is 5
}
if ( i == 8) {
cout << " Breaking at 8\ n " ;
break ; // Exit the loop completely when i is 8
}
cout << " Current value : " << i << endl ;
}
return 0;
}

2.10 Namespace scope


Namespaces in C++ are used to organize code and avoid name conflicts, especially in
large projects or when using libraries. Key Points:

• Namespaces define a scope for identifiers like variables, functions, classes, etc.

• The std namespace contains all the standard C++ library identifiers.

• You can define your own namespace to group related code.

• Use the scope resolution operator (::) to access elements within a namespace.

Listing 31: Accessing Variable Using Namespace


# include < iostream >
using namespace std ;

namespace mynamespace {
int a = 10;
}

int main () {
cout << mynamespace :: a ;
return 0;
}

Listing 32: Using using namespace for Easier Access


# include < iostream >
using namespace std ;

namespace mynamespace {
int a = 10;
}

using namespace mynamespace ;

int main () {
cout << a ;
return 0;
}

47
Chapter 2: Basics of c++ Programming Object Oriented Programming

Listing 33: Namespace with variable and function


# include < iostream >
using namespace std ;

namespace First {
int value = 10;
void display () {
cout << " First namespace value : " << value << endl ;
}
}

namespace Second {
int value = 20;
void display () {
cout << " Second namespace value : " << value << endl ;
}
}

int main () {
First :: display () ; // Calls First 's display ()
Second :: display () ; // Calls Second 's display ()
return 0;
}

2.11 Functions
A function groups a number of program statements into a unit and gives it a name. This
unit can then be invoked from other parts of the program.

Figure 30: Flow of control to a function

Functions in C++ (and C) are similar to subroutines and procedures in various other
languages.

48
Chapter 2: Basics of c++ Programming Object Oriented Programming

Figure 31: Function Syntax

// Program to check whether a number is positive or not

# include < iostream >


using namespace std ;

// Function that returns true if the number is positive , false


otherwise
bool isPositive ( int number ) {
if ( number > 0) {
return true ;
} else {
return false ;
}
}

int main () {
int num ;
cout << " Enter a number : " ;
cin >> num ;

if ( isPositive ( num ) ) {
cout << " The number is positive . " << endl ;
} else {
cout << " The number is zero or negative . " << endl ;
}

return 0;
}

49
Chapter 2: Basics of c++ Programming Object Oriented Programming

2.11.1 Function Overloading


An overloaded function appears to perform different activities depending on the kind of
data sent to it. It performs one operation on one kind of data but another operation on
a different kind.

• Different Numbers of Arguments:


Listing 34: Function Overloading: Area()
# include < iostream >
using namespace std ;

// Area of a square
int Area ( int side ) {
return side * side ;
}

// Area of a rectangle
int Area ( int length , int width ) {
return length * width ;

int main () {
cout << " Area of square : " << Area (5) << endl ;
cout << " Area of rectangle : " << Area (5 , 10) << endl ;
return 0;
}

The program contains two functions with the same name. There are two function
calls, and two definitions. What keeps the compiler from becoming hopelessly
confused? It uses the function signature—the number of arguments, and their
data types—to distinguish one function from another. The compiler, seeing several
functions with the same name but different numbers of arguments, could decide the
programmer had made a mistake (which is what it would do in C). Instead, it very
tolerantly sets up a separate function for every such definition. Which one of these
functions will be called depends on the number of arguments supplied in the call.

• Different Kinds of Arguments: The compiler can also distinguish between


overloaded functions with the same number of arguments, provided their type is
different.
Listing 35: Overloading Area() with Different Argument Types
# include < iostream >
using namespace std ;

// Area of a square ( int )


int Area ( int side ) {
return side * side ;
}

// Area of a circle ( double )


double Area ( double radius ) {
return 3.14159 * radius * radius ;
}

50
Chapter 2: Basics of c++ Programming Object Oriented Programming

int main () {
cout << " Area of square : " << Area (5) << endl ; //
int
cout << " Area of circle : " << Area (7.0) << endl ; //
double
return 0;
}

2.11.2 Inline Function


To save execution time in short functions, you may elect to put the code in the function
body directly inline with the code in the calling program. That is, each time there’s a
function call in the source file, the actual code from the function is inserted, instead of
a jump to the function. The difference between a function and inline code is shown in
Figure

Figure 32: Function Vs Inline code

Long sections of repeated code are generally better off as normal functions: The
savings in memory space is worth the comparatively small sacrifice in execution speed.
But making a short section of code into an ordinary function may result in little savings
in memory space, while imposing just as much time penalty as a larger function. In fact,
if a function is very short, the instructions necessary to call it may take up as much space
as the instructions within the function body, so that there is not only a time penalty
but a space penalty as well. In such cases you could simply repeat the necessary code
in your program, inserting the same group of statements wherever it was needed. The
trouble with repeatedly inserting the same code is that you lose the benefits of program
organization and clarity that come with using functions. The program may run faster
and take less space, but the listing is longer and more complex.

51
Chapter 2: Basics of c++ Programming Object Oriented Programming

The solution to this quandary is the inline function. This kind of function is written
like a normal function in the source file but compiles into inline code instead of into a
function. The source file remains well organized and easy to read, since the function is
shown as a separate entity. However, when the program is compiled, the function body
is actually inserted into the program wherever a function call occurs.
It’s easy to make a function inline: All you need is the keyword inline in the function
definition:
// Inline function definition
inline int square ( int x ) {
return x * x ;
}

int main () {
int num = 5;
int result = square ( num ) ;
return 0;
}

2.11.3 Defaults Arguments


Default arguments allow functions to be called with fewer arguments than they are defined
to accept by providing default values in the function declaration or definition.
# include < iostream >
using namespace std ;

// Function declaration with default arguments


void display ( int a , int b = 10 , int c = 20) ;

int main () {
display (5) ; // Output : a = 5 , b = 10 , c = 20
display (5 , 15) ; // Output : a = 5 , b = 15 , c = 20
display (5 , 15 , 25) ; // Output : a = 5 , b = 15 , c = 25
return 0;
}

// Function definition
void display ( int a , int b , int c ) {
cout << " a = " << a << " , b = " << b << " , c = " << c << endl ;
}

• Default arguments must be provided from right to left.

• You cannot provide a default for a parameter followed by a non-defaulted parameter.

// Invalid : b has default , c does not


void display ( int a , int b = 10 , int c ) ; // Compilation error

// Invalid : a has default , b and c do not


void display ( int a = 5 , int b , int c ) ; // Compilation error

52
Chapter 2: Basics of c++ Programming Object Oriented Programming

// Declaration
void display ( int a , int b = 10 , int c = 20) ;

// Error : redefinition of default values


void display ( int a , int b = 15 , int c = 25) {
// ...
}

2.11.4 Scope and Storage Class:


Now that we know about functions, we can explore two features of C++ that are related
to the interaction of variables and functions: scope and storage class. The scope of
a variable determines which parts of the program can access it, and its storage class
determines how long it stays in existence. We’ll summarize this briefly and then look at
the situation in more detail.
Two different kinds of scope are important here: local and file. (We’ll see another
one, class scope, later.)

• Variables with local scope are visible only within a block.

• Variables with file scope are visible throughout a file.

A block is basically the code between an opening brace { and a closing brace }. Thus,
a function body is a block.
There are two storage classes: automatic and static.

• Variables with storage class automatic exist during the lifetime of the function
in which they’re defined.

• Variables with storage class static exist for the lifetime of the program.

Table 10: Comparison of Storage Types in C++

Property Local Static Local Global


Visibility Function Function File
Lifetime Function Program Program
Initialized Value Not initialized 0 0

2.11.5 Pass by reference and Return by reference


Passing arguments by reference uses a different mechanism. Instead of a value being
passed to the function, a reference to the original variable, in the calling program, is
passed. (It’s actually the memory address of the variable that is passed, although you
don’t need to know this.)
An important advantage of passing by reference is that the function can access the
actual variables in the calling program. Among other benefits, this provides a mechanism
for passing more than one value from the function back to the calling program.

53
Chapter 2: Basics of c++ Programming Object Oriented Programming

# include < iostream >


using namespace std ;

// Function that swaps two integers by reference


void swap ( int &x , int & y ) {
int temp = x ;
x = y;
y = temp ;
}

int main () {
int a = 10 , b = 20;
cout << " Before swap : a = " << a << " , b = " << b << endl ;

swap (a , b ) ; // Call by reference

cout << " After swap : a = " << a << " , b = " << b << endl ;
return 0;
}

Output:
Before swap: a = 10, b = 20
After swap: a = 20, b = 10
Problem: Write a function that calculates the sum, difference, and product of two
integers and returns all three using reference parameters.
# include < iostream >
using namespace std ;

// Function definition
void calculate ( int a , int b , int & sum , int & diff , int & prod ) {
sum = a + b ;
diff = a - b ;
prod = a * b ;
}

int main () {
int num1 , num2 ;
int sum , difference , product ;

cout << " Enter two integers : " ;


cin >> num1 >> num2 ;

calculate ( num1 , num2 , sum , difference , product ) ;

cout << " Sum = " << sum << endl ;


cout << " Difference = " << difference << endl ;
cout << " Product = " << product << endl ;

return 0;
}

Returning by Reference:
Returning by reference allows us to use a function call on the left sign side of the equal
sign. The following example demonstrates how to return a reference from a function:

54
Chapter 2: Basics of c++ Programming Object Oriented Programming

# include < iostream >


using namespace std ;

int x ; // global variable


int & setx () ; // function declaration

int main ()
{
// set x to a value , using function call on left side
setx () = 92;
cout << " x = " << x << endl ; // display new value in x
return 0;
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int & setx ()
{
return x ; // returns the value to be modified
}

Explanation:

• The function setx() returns a reference to the global variable x.

• This allows the function call setx() to appear on the left-hand side of an assign-
ment.

• Therefore, setx() = 92; assigns the value 92 directly to x.

2.12 Array, pointer and string


2.12.1 Array
In computer languages we also need to group together data items of the same type. The
most basic mechanism that accomplishes this in C++ is the array. Arrays exist in almost
every computer language. Arrays in C++ are similar to those in other languages, and
identical to those in C.
Listing 36: Getting and Displaying Array Elements
# include < iostream >
using namespace std ;

int main ()
{
int age [4]; // array ' age ' of 4 ints
for ( int j = 0; j < 4; j ++) // get 4 ages
{
cout << " Enter an age : " ;
cin >> age [ j ]; // access array element
}
for ( int j = 0; j < 4; j ++) // display 4 ages
cout << " You entered " << age [ j ] << endl ;
return 0;
}

55
Chapter 2: Basics of c++ Programming Object Oriented Programming

Figure 33: Syntax of Array

Figure 34: Elements of array

Listing 37: Array Initialization Examples


# include < iostream >
using namespace std ;

int main ()
{
// Initialization with explicit values
int numbers [5] = {1 , 2 , 3 , 4 , 5};

// Partial initialization ( remaining elements set to 0)


int scores [5] = {10 , 20};

// Zero initialization
int zeros [5] = {0};

// Implicit size ( compiler counts elements )


int days [] = {1 , 2 , 3 , 4 , 5 , 6 , 7};

return 0;
}

56
Chapter 2: Basics of c++ Programming Object Oriented Programming

Figure 35: Syntax of Array Initialization

So far we’ve looked at arrays of one dimension: A single variable specifies each array
element. But arrays can have higher dimensions.
// displays sales chart using 2 - d array
# include < iostream >
# include < iomanip > // for setprecision , etc .
using namespace std ;

const int DISTRICTS = 4; // array dimensions


const int MONTHS = 3;

int main ()
{
int d , m ;
double sales [ DISTRICTS ][ MONTHS ]; // two - dimensional array definition

cout << endl ;


for ( d = 0; d < DISTRICTS ; d ++) // get array values
for ( m = 0; m < MONTHS ; m ++)
{
cout << " Enter sales for district " << d + 1;
cout << " , month " << m + 1 << " : " ;
cin >> sales [ d ][ m ]; // put number in array
}

cout << " \ n \ n " ;


cout << setw (30) << " Month \ n " ;
cout << setw (20) < <1 < < setw (10) < <2 < < setw (10) < <3;

for ( d = 0; d < DISTRICTS ; d ++)


{
cout << " \ nDistrict " << d + 1;
for ( m = 0; m < MONTHS ; m ++) // display array values
cout << fixed
<< setprecision (2) // digits to right
<< setw (10) // field width
<< sales [ d ][ m ]; // get number from
array
}

cout << endl ;


return 0;
} // end main

57
Chapter 2: Basics of c++ Programming Object Oriented Programming

Figure 36: Two Dimensional Array

Listing 38: 2D Array Initialization


int matrix [3][4] = {
{1 , 2 , 3 , 4} ,
{5 , 6 , 7 , 8} ,
{9 , 10 , 11 , 12}
};

int matrix [3][4] = {


{1 , 2} , // rest will be zero
{5 , 6 , 7} ,
{9}
};

int matrix [3][4] = {


1, 2, 3, 4,
5, 6, 7, 8,
9 , 10 , 11 , 12
};

int matrix [][4] = {


{1 , 2 , 3 , 4} ,
{5 , 6 , 7 , 8} ,
{9 , 10 , 11 , 12}
};

int matrix [3][4] = {0};

2.12.2 Pointers
Pointers are an important feature of C++ (and C), while many other languages, such as
Visual Basic and Java, have no pointers at all. A variable that holds an address value is
called a pointer variable, or simply a pointer.
Listing 39: Pointer Basics: Printing Addresses Using a Pointer
# include < iostream >

58
Chapter 2: Basics of c++ Programming Object Oriented Programming

using namespace std ;

int main ()
{
int var1 = 11; // two integer variables
int var2 = 22;

// print addresses of variables


cout << & var1 << endl
<< & var2 << endl << endl ;

int * ptr ; // pointer to integers


ptr = & var1 ; // pointer points to var1
cout << ptr << endl ; // print pointer value

ptr = & var2 ; // pointer points to var2


cout << ptr << endl ; // print pointer value

return 0;
}

Figure 37: Pointer Variable

• int* ptr;
This declares a pointer variable named ptr that can store the address of an int
type variable. The asterisk * indicates that ptr is not a regular integer variable,
but a pointer to an integer.

59
Chapter 2: Basics of c++ Programming Object Oriented Programming

• ptr = &var1;
This assigns the address of the variable var1 to the pointer ptr.
The ampersand & is the ”address-of” operator, which returns the memory address
of the variable var1.
After this statement, ptr holds the address of var1, and *ptr can be used to access
the value of var1.

Listing 40: Accessing the Variable Pointed to by a Pointer


# include < iostream >
using namespace std ;

int main ()
{
int var1 = 11; // two integer variables
int var2 = 22;
int * ptr ; // pointer to integers

ptr = & var1 ; // pointer points to var1


cout << * ptr << endl ; // print contents of pointer (11)

ptr = & var2 ; // pointer points to var2


cout << * ptr << endl ; // print contents of pointer (22)

return 0;
}

• *ptr (Dereferencing Operator):


The asterisk * in this context is the dereference operator. It is used to access the
value stored at the memory address held by the pointer ptr.

– If ptr = &var1;, then *ptr refers to var1, and *ptr will give the value 11.
– If ptr = &var2;, then *ptr refers to var2, and *ptr will give the value 22.

So, cout << *ptr; will output the value stored in the variable to which ptr cur-
rently points.

Listing 41: Assigning and Accessing Values Using Pointers


# include < iostream >
using namespace std ;

int main ()
{
int var1 , var2 ; // two integer variables
int * ptr ; // pointer to integers

ptr = & var1 ; // set pointer to address of var1


* ptr = 37; // same as var1 = 37
var2 = * ptr ; // same as var2 = var1

cout << var2 << endl ; // verify var2 is 37

return 0;
}

60
Chapter 2: Basics of c++ Programming Object Oriented Programming

Figure 38: Accessing Via Pointers

Listing 42: Accessing Array Elements Using Pointer Arithmetic


# include < iostream >
using namespace std ;

int main ()
{
// array
int intarray [5] = { 31 , 54 , 77 , 52 , 93 };

for ( int j = 0; j < 5; j ++) // for each element ,


cout << *( intarray + j ) << endl ; // print value

return 0;
}

2.12.3 Strings
The are two kinds of strings commonly used in c++: c strings and strings that are objects
of the string class.

• C-Strings(C-style strings): As with other data types, strings can be variables


or constants.
Listing 43: Simple String Input Using Character Array
# include < iostream >

61
Chapter 2: Basics of c++ Programming Object Oriented Programming

Figure 39: String stored in string variable

using namespace std ;

int main ()
{
const int MAX = 80; // max characters in string
char str [ MAX ]; // string variable str

cout << " Enter a string : " ;


cin >> str ; // put string in str

// display string from str


cout << " You entered : " << str << endl ;

return 0;
}

Listing 44: Avoiding Buffer Overflow with cin.width and setw


# include < iostream >
# include < iomanip > // for setw
using namespace std ;

int main ()
{
const int MAX = 20; // max characters in string
char str [ MAX ]; // string variable str

cout << " \ nEnter a string : " ;


cin >> setw ( MAX ) >> str ; // put string in str ,
// no more than MAX chars

cout << " You entered : " << str << endl ;

62
Chapter 2: Basics of c++ Programming Object Oriented Programming

return 0;
}

Listing 45: Reading a String with Embedded Blanks Using cin.get


# include < iostream >
using namespace std ;

int main ()
{
const int MAX = 80; // max characters in string
char str [ MAX ]; // string variable str

cout << " \ nEnter a string : " ;


cin . get ( str , MAX ) ; // put string in str

cout << " You entered : " << str << endl ;
return 0;
}

Listing 46: Reading Multiple Lines Terminated by ’$’ Character


# include < iostream >
using namespace std ;

const int MAX = 2000; // max characters in string


char str [ MAX ]; // string variable str

int main ()
{
cout << " \ nEnter a string :\ n " ;
cin . get ( str , MAX , '$ ') ; // terminate with $
cout << " You entered :\ n " << str << endl ;
return 0;
}

Listing 47: Copying a string using strcpy() function


# include < iostream >
# include < cstring > // for strcpy ()
using namespace std ;

int main ()
{
char str1 [] = " Tiger , tiger , burning bright \ n "
" In the forests of the night " ;
const int MAX = 80; // size of str2 buffer
char str2 [ MAX ]; // empty string
strcpy ( str2 , str1 ) ; // copy str1 to str2
cout << str2 << endl ; // display str2
return 0;
}

63
Chapter 2: Basics of c++ Programming Object Oriented Programming

• The Standard C++ string Class: Standard C++ includes a new class called
string. This class improves on the traditional Cstring in many ways. For one thing,
you no longer need to worry about creating an array of the right size to hold string
variables. The string class assumes all the responsibility for memory management.
Listing 48: Defining and assigning std::string objects
# include < iostream >
# include < string >
using namespace std ;

int main ()
{
string s1 ( " Man " ) ; // initialize
string s2 = " Beast " ; // initialize
string s3 ;
s3 = s1 ; // assign
cout << " s3 = " << s3 << endl ;

s3 = " Neither " + s1 + " nor " ; // concatenate


s3 += s2 ; // concatenate
cout << " s3 = " << s3 << endl ;

s1 . swap ( s2 ) ; // swap s1 and s2


cout << s1 << " nor " << s2 << endl ;

return 0;
}

s3 = Man
s3 = Neither Man nor Beast
Beast nor Man

Input/Output with string Objects:


// string class input / output
# include < iostream >
# include < string > // for string class
using namespace std ;
int main ()
{
// objects of string class
string full_name , nickname , address ;
string greeting ( " Hello , " ) ;

cout << " Enter your full name : " ;


getline ( cin , full_name ) ; // reads embedded blanks

cout << " Your full name is : " << full_name << endl ;

cout << " Enter your nickname : " ;


cin >> nickname ; // input to string object

greeting += nickname ; // append name to greeting

cout << greeting << endl ; // output : " Hello , Jim "

64
Chapter 2: Basics of c++ Programming Object Oriented Programming

cout << " Enter your address on separate lines \ n " ;


cout << " Terminate with '$ '\ n " ;
getline ( cin , address , '$ ') ; // reads multiple lines

cout << " Your address is : " << address << endl ;
return 0;
}

Enter your full name: Ram Thapa


Your full name is: Ram Thapa
Enter your nickname: Rame
Hello, Rame
Enter your address on separate lines
Terminate with '$'
Dharan-16$
Your address is:
Dharan-16

Table 11: Commonly Used std::string Operations

Category Operation Description


Creation string s; Default constructor
string s("text"); Initialize with string literal
Input/Output getline(cin, s); Read entire line into string
cin >> s; Read word (no spaces)
Concatenation s1 + s2 Join two strings
s += s2 Append string
Access s[i] Access character at index
s.at(i) Safe access with bounds checking
Modification s.insert(pos, str) Insert string at position
s.erase(pos, len) Remove characters
s.replace(pos,len,str) Replace part of string
Comparison s1 == s2 Equality check
s1 < s2 Lexicographical comparison
Size s.size(), s.length() Get length of string
Search s.find("sub") Find substring position
s.rfind("sub") Find from end
Substring s.substr(pos, len) Extract part of string
Clear/Empty s.clear() Remove all characters
s.empty() Check if string is empty
Conversion stoi(s), to string(n) String to int, int to string

2.13 Structure and unions


A structure is a collection of simple variables. The variables in a structure can be of
different types. The data items in a structure are called the members of the structure.

65
Chapter 2: Basics of c++ Programming Object Oriented Programming

In books on C programming, structures are often considered an advanced feature and


are introduced toward the end of the book. However, for C++ programmers, structures
are one of the two important building blocks in the understanding of objects and classes.
In fact, the syntax of a structure is almost identical to that of a class. A structure
(as typically used) is a collection of data, while a class is a collection of both data and
functions. So by learning about structures we’ll be paving the way for an understanding
of classes and objects.
Listing 49: Using Structures in C++
# include < iostream >
using namespace std ;

struct part // declare a structure


{
int modelnumber ; // ID number of widget
int partnumber ; // ID number of widget part
float cost ; // cost of part
};

int main ()
{
part part1 ; // define a structure variable
part1 . modelnumber = 6244; // give values to structure members
part1 . partnumber = 373;
part1 . cost = 217.55 F ;

// display structure members


cout << " Model " << part1 . modelnumber ;
cout << " , part " << part1 . partnumber ;
cout << " , costs $ " << part1 . cost << endl ;

return 0;
}

Output:

Model 6244, part 373, costs $217.55

Figure 40: Syntax of structure.

66
Chapter 2: Basics of c++ Programming Object Oriented Programming

One of the aims of C++ is to make the syntax and the operation of user-defined data
types as similar as possible to that of built-in data types. (In C you need to include the
keyword struct in structure definitions, as in struct part part1;. In C++ the keyword is
not necessary.)

Figure 41: Structure member in memory.

Once a structure variable has been defined, its members can be accessed using some-
thing called the dot operator as shown in Figure 42.

67
Chapter 2: Basics of c++ Programming Object Oriented Programming

Figure 42: Dot Operator

Initialization and Assignment of Structure Variables

Listing 50: Initializing and Assigning Structure Variables


# include < iostream >
using namespace std ;

struct part // specify a structure


{
int modelnumber ; // ID number of widget
int partnumber ; // ID number of widget part
float cost ; // cost of part
};

int main ()
{
// initialize variable
part part1 = { 6244 , 373 , 217.55 F };
part part2 ; // define another variable

// display first variable

68
Chapter 2: Basics of c++ Programming Object Oriented Programming

cout << " Model " << part1 . modelnumber ;


cout << " , part " << part1 . partnumber ;
cout << " , costs $ " << part1 . cost << endl ;

part2 = part1 ; // assign first variable to second

// display second variable


cout << " Model " << part2 . modelnumber ;
cout << " , part " << part2 . partnumber ;
cout << " , costs $ " << part2 . cost << endl ;

return 0;
}

Output:

Model 6244, part 373, costs $217.55


Model 6244, part 373, costs $217.55

Question:
Write a C++ program that uses nested structures to represent a rectangular room’s
dimensions in feet and inches. Define a Distance structure with members for feet and
inches, and a Room structure that contains two Distance members: one for length and
one for width. Your program should:

• Prompt the user (or directly assign) the length and width of the room in feet and
inches

• Convert these dimensions entirely into decimal feet (feet + inches/12)

• Calculate and display the area of the room in square feet.

Listing 51: Demonstrating Nested Structures


# include < iostream >
using namespace std ;

struct Distance // English distance


{
int feet ;
float inches ;
};

struct Room // rectangular area


{
Distance length ; // length of rectangle
Distance width ; // width of rectangle
};

int main ()
{
Room dining ; // define a room

// assign values to room


dining . length . feet = 13;
dining . length . inches = 6.5;
dining . width . feet = 10;

69
Chapter 2: Basics of c++ Programming Object Oriented Programming

dining . width . inches = 0.0;

// convert length & width to decimal feet


float l = dining . length . feet + dining . length . inches / 12;
float w = dining . width . feet + dining . width . inches / 12;

// find area and display it


cout << " Dining room area is " << l * w << " square feet \ n " ;
return 0;
}

Output:
Dining room area is 143.25 square feet

Figure 43: Dot operator and Nested Structure

2.14 Enumeration
As we’ve seen, structures can be looked at as a way to provide user-defined data types.
A different approach to defining your own data type is the enumeration. Enumerated
types work when you know in advance a finite (usually short) list of values that a data
type can take on.
Listing 52: Demonstrating Enum Types and Operations
# include < iostream >

70
Chapter 2: Basics of c++ Programming Object Oriented Programming

using namespace std ;

// specify enum type


enum days_of_week { Sun , Mon , Tue , Wed , Thu , Fri , Sat };

int main ()
{
days_of_week day1 , day2 ; // define variables of type days_of_week
day1 = Mon ; // give values to variables
day2 = Thu ;

int diff = day2 - day1 ; // can do integer arithmetic


cout << " Days between = " << diff << endl ;

if ( day1 < day2 ) // can do comparisons


cout << " day1 comes before day2 \ n " ;

return 0;
}

Days between = 3
day1 comes before day2

Figure 44: Syntax of enum specifier

An enum declaration defines the set of all names that will be permissible values of the
type. These permissible values are called enumerators. The enum type days of week has
seven enumerators: Sun, Mon, Tue, and so on, up to Sat. An enumerators is a list of all
possible values.

71
Chapter 2: Basics of c++ Programming Object Oriented Programming

Figure 45: enum vs int

Enumerations are treated internally as integers. This explains why you can perform
arithmetic and relational operations on them. Ordinarily the first name in the list is
given the value 0, the next name is given the value 1, and so on.
However, C++ allows you to assign custom values to enumeration constants, including
changing the starting value or assigning specific values to individual members.

Note: Once a value is explicitly assigned to an enum member, the subsequent members
(if not explicitly assigned) continue incrementing from that value.

Example:
Listing 53: Enumeration with Custom Starting Values
# include < iostream >
using namespace std ;

enum Status {
Pending = 10 ,
Approved ,
Rejected = 100 ,
Cancelled
};

72
Chapter 2: Basics of c++ Programming Object Oriented Programming

int main () {
cout << " Pending = " << Pending << endl ;
cout << " Approved = " << Approved << endl ;
cout << " Rejected = " << Rejected << endl ;
cout << " Cancelled = " << Cancelled << endl ;
return 0;
}

Sample Output:

Pending = 10
Approved = 11
Rejected = 100
Cancelled = 101

Explanation:

• Pending is explicitly assigned the value 10.

• Approved automatically gets the next value, 11.

• Rejected is explicitly set to 100.

• Cancelled follows Rejected and gets the next value, 101.

This flexibility is useful when mapping enumeration values to specific codes in an appli-
cation or protocol, such as status codes, error codes, or menu options.
Listing 54: Word Count in a String
# include < iostream >
# include < string >
using namespace std ;

enum itsaWord { NO , YES }; // NO =0 , YES =1

int main () {
itsaWord isWord = NO ;
int wordcount = 0;

// The input string with extra spaces


string phrase = " I Love C ++ Program ";
cout << " Phrase : " << phrase << endl ;

for ( int i = 0; i < phrase . length () ; i ++) {


char ch = phrase [ i ];
if ( ch == ' ') { // If whitespace
if ( isWord == YES ) { // If we were in a word
wordcount ++; // End of a word
isWord = NO ; // Reset flag
}
} else { // Normal character
if ( isWord == NO ) // Start of a new word
isWord = YES ;
}
}

73
Chapter 2: Basics of c++ Programming Object Oriented Programming

// If the string ends with a word , count it


if ( isWord == YES )
wordcount ++;

cout << " --- Word count is " << wordcount << " ---" << endl ;

return 0;
}

The program counts the number of words in a hard-coded string. It correctly handles
leading, trailing, and multiple intermediate spaces.
Sample Output:

Phrase: I Love C++ Program


--- Word count is 4 ---

Question:
Write a C++ program using an enum to represent three geometric shapes — CIRCLE,
SQUARE, and TRIANGLE. The program should let the user guess a secret shape by
entering a number (1 to 3), and then check if the guess matches the secret shape. If it
matches, display a success message; otherwise, display a failure message. Use a function
checkGuess() that returns true if the guess is correct, otherwise false.
# include < iostream >
using namespace std ;

enum SecretShape {
CIRCLE ,
SQUARE ,
TRIANGLE
};

bool checkGuess ( SecretShape playerGuess , SecretShape actualSecret ) {


return playerGuess == actualSecret ;
}

int main () {
SecretShape secret = TRIANGLE ;
SecretShape playerGuess ;
int guess ;

cout < < " Guess a Shape (1. Circle ,2. Square ,3. Triangle ) " ;
cin > > guess ;

switch ( guess )
{
case 1 : playerGuess = CIRCLE ; break ;
case 2 : playerGuess = SQUARE ; break ;
case 3 : playerGuess = TRIANGLE ; break ;
}

if ( checkGuess ( playerGuess , secret ) ) {


cout << " Correct ! You guessed the secret shape ! " << endl ;
} else {
cout << " Incorrect . Try again ! " << endl ;
}

74
Chapter 2: Basics of c++ Programming Object Oriented Programming

return 0;
}

2.15 Dynamic memory allocation


In C++, arrays are commonly used to reserve memory for storing data elements of the
same type. For example, the following statement:
int arr1 [100];

reserves memory space for 100 integers. This approach is simple and efficient when
the required size is known in advance.

However, arrays have a major limitation: The size of the array must be known at
compile time. This means that the programmer must decide how large the array will be
before the program runs.

It is not possible to wait until runtime to specify the array size using static arrays. This
makes arrays inflexible for programs where the amount of data is only known during
execution.

To overcome this limitation, dynamic memory allocation is used, where memory is


allocated during the execution of the program using pointers and operators like new and
delete.
The new Operator: C++ provides a different approach to obtaining blocks of
memory: the new operator. This versatile operator obtains memory from the operating
system and returns a pointer to its starting point.
// introduces operator new
# include < iostream >
# include < cstring > // for strlen
using namespace std ;

int main ()
{
char * str = " Idle hands are the devil 's workshop . " ;
int len = strlen ( str ) ; // get length of str
char * ptr ; // make a pointer to char

ptr = new char [ len + 1]; // set aside memory : string + '\0 '
strcpy ( ptr , str ) ; // copy str to new memory area ptr

cout << " ptr = " << ptr << endl ; // show that ptr is now pointing to
str 's copy

delete [] ptr ; // release ptr 's memory

return 0;
}

75
Chapter 2: Basics of c++ Programming Object Oriented Programming

Figure 46: The new operator

Figure 47: Memory allocated by new operator

The delete Operator: If your program reserves many chunks of memory using
new, eventually all the available memory will be reserved and the system will crash. To
ensure safe and efficient use of memory, the new operator is matched by a corresponding
delete operator that returns memory to the operating system. In the statement

delete[] ptr;

returns to the system whatever memory was pointed to by ptr.


Actually, there is no need for this operator in above program, since memory is au-
tomatically returned when the program terminates. However, suppose you use new in a
function. If the function uses a local variable as a pointer to this memory, the pointer will

76
Chapter 2: Basics of c++ Programming Object Oriented Programming

be destroyed when the function terminates, but the memory will be left as an orphan,
taking up space that is inaccessible to the rest of the program. Thus it is always good
practice, and often essential, to delete memory when you’re through with it.
The brackets following delete indicate that we’re deleting an array. If you create a
single object with new, you don’t need the brackets when you delete it.
# include < iostream >
using namespace std ;

int main () {
int size ;

cout << " Enter the size of the array : " ;


cin >> size ;

// Allocate memory for the array dynamically


int * arr = new int [ size ];

// Input elements
cout << " Enter " << size << " integers :\ n " ;
for ( int i = 0; i < size ; ++ i ) {
cin >> arr [ i ];
}

// Display elements
cout << " You entered : " ;
for ( int i = 0; i < size ; ++ i ) {
cout << arr [ i ] << " " ;
}
cout << endl ;

// Deallocate the memory


delete [] arr ;

return 0;
}

77
Chapter 2: Basics of c++ Programming Object Oriented Programming

Points to Remember
• In C++, floating-point literals like 1.123 are of type double by default. To assign
them to a float, use the suffix f (e.g., 1.123f).

• When a double literal (e.g., 10.54) is assigned to a float variable (e.g., float
a = 10.54;), it is implicitly converted to float. This is a narrowing conversion,
which may lead to loss of precision and is considered an unusual implicit conversion
that C++ allows.

• In C, structures require the keyword struct during variable declaration (e.g.,


struct Student s1;), but in C++, you can directly use the tag name as a type
(e.g., Student s1;) same goes for enum also.

• setprecision() controls the total number of significant digits by default. To


control the number of digits after the decimal point, combine it with fixed or
scientific.

• Function overloading becomes ambiguous when passing 3.5 (a double) instead


of 3.5f (a float) because the compiler may not clearly decide which overloaded
version (for float or double) to call.

• Implicit type conversions occur automatically (e.g., int to float); use casting
(static cast<type>(value)) for safe explicit conversions.

• Pointers store memory addresses and can be reassigned or null; references are aliases
that must be initialized and cannot be changed.

• Arrays are fixed-size collections; pointers can dynamically manage memory using
new and delete.

• Strings in C++ can be handled via character arrays or the std::string class for
easier manipulation.

• Enumerations can start from custom values; the next values increment from the
previous unless specified.

• Dynamic memory allocation in C++ uses new (e.g., int *p = new int;) and must
be released with delete.

78
Chapter 3: Objects and Classes Object Oriented Programming

Chapter 3: Objects and Classes


3.1 C++ classes
Our first program contains a class and two objects of that class. Although it’s simple,
the program demonstrates the syntax and general features of classes in C++.
Listing 55: Demonstration of class
// demonstrates a small , simple object
# include < iostream >
using namespace std ;

class smallobj // define a class


{
private :
int somedata ; // class data
public :
void setdata ( int d ) // member function to set data
{ somedata = d ; }
void showdata () // member function to display data
{ cout << " Data is " << somedata << endl ; }
};

int main ()
{
smallobj s1 , s2 ; // define two objects of class smallobj
s1 . setdata (1066) ; // call member function to set data
s2 . setdata (1776) ;
s1 . showdata () ; // call member function to display data
s2 . showdata () ;
return 0;
}

The class smallobj defined in this program contains one data item and two member
functions. The two member functions provide the only access to the data item from
outside the class. The first member function sets the data item to a value, and the
second displays the value. Placing data and functions together into a single entity is a
central idea in object-oriented programming. This is shown in Figure 48

79
Chapter 3: Objects and Classes Object Oriented Programming

Figure 49: Syntax of Class

Figure 48: Class contains data and functions.

The definition starts with the keyword class, followed by the class name—smallobj
in this example. Like a structure, the body of the class is delimited by braces and
terminated by a semicolon. A key feature of object-oriented programming is data hiding.
The primary mechanism for hiding data is to put it in a class and make it private.
Private data or functions can only be accessed from within the class. Public data or
functions, on the other hand, are accessible from outside the class. This is shown in
Figure 50

80
Chapter 3: Objects and Classes Object Oriented Programming

Figure 50: Private and Public

• Class Data: The smallobj class contains one data item: somedata, which is of
type int. The data items within a class are called data members (or sometimes
member data). There can be any number of data members in a class, just as there
can be any number of data items in a structure. The data member somedata
follows the keyword private, so it can be accessed from within the class, but not
from outside.
• Member Functions: Member functions are functions that are included within
a class. (In some object-oriented languages, such as Smalltalk, member functions
are called methods; some writers use this term in C++ as well.) There are two
member functions in smallobj: setdata() and showdata(). The function bodies
of these functions have been written on the same line as the braces that delimit
them. Because setdata() and showdata() follow the keyword public, they can
be accessed from outside the class.
Functions Are Public, Data Is Private
Usually the data within a class is private and the functions are public. This is a result
of the way classes are used. The data is hidden so it will be safe from accidental manip-
ulation, while the functions that operate on the data are public so they can be accessed
from outside the class. However, there is no rule that says data must be private and func-
tions public; in some circumstances you may find you’ll need to use private functions and
public data. Note that the member functions setdata() and showdata() are definitions
in that the actual code for the function is contained within the class definition. Mem-
ber functions defined inside a class this way are created as inline functions by default.
We’ll see later that it is also possible to declare a function within a class but to define it
elsewhere. Functions defined outside the class are not normally inline.

3.2 Objects and the member access


Object has the same relationship to a class that a variable has to a data type. An object
is said to be an instance of a class, in the same way my 2025 Royal enfield Bullet 250
is an instance of a vehicle. In above program, the class—whose name is smallobj—is
defined in the first part of the program. Later, in main(), we define two objects—s1 and
s2—that are instances of that class.
Each of the two objects is given a value, and each displays its value. Here’s the output
of the program:

81
Chapter 3: Objects and Classes Object Oriented Programming

Data is 1066 ← object s1 displayed this


Data is 1776 ← object s2 displayed this

The next two statements in main() call the member function setdata():

s1.setdata(1066);
s2.setdata(1776);

To use a member function, the dot operator (the period) connects the object name
and the member function. The syntax is similar to the way we refer to structure members,
but the parentheses signal that we’re executing a member function rather than referring
to a data item. (The dot operator is also called the class member access operator.)

Figure 51: Two objects s1 and s2

Here’s another kind of entity C++ objects can represent: variables of a user-defined
data type.
// Distance class
# include < iostream >
using namespace std ;

class Distance // English Distance class


{
private :
int feet ;
float inches ;
public :
void setdist ( int ft , float in ) // set Distance to args
{ feet = ft ; inches = in ; }

void getdist () // get length from user

82
Chapter 3: Objects and Classes Object Oriented Programming

{
cout << " \ nEnter feet : " ; cin >> feet ;
cout << " Enter inches : " ; cin >> inches ;
}

void showdist () // display distance


{ cout << feet << " \ ' - " << inches << ' \" '; }
};

int main ()
{
Distance dist1 , dist2 ; // define two lengths
dist1 . setdist (11 , 6.25) ; // set dist1
dist2 . getdist () ; // get dist2 from user

// display lengths
cout << " \ ndist1 = " ; dist1 . showdist () ;
cout << " \ ndist2 = " ; dist2 . showdist () ;
cout << endl ;
return 0;
}

3.3 Relation of object, class and memory


Each object has its own separate data items. On the other hand, all the objects in a
given class use the same member functions. The member functions are created and placed
in memory only once—when they are defined in the class definition. This makes sense;
there’s really no point in duplicating all the member functions in a class every time you
create another object of that class, since the functions for each object are identical. The
data items, however, will hold different values, so there must be a separate instance of
each data item for each object. Data is therefore placed in memory when each object is
defined, so there is a separate set of data for each object. Figure 52 shows how this looks.

83
Chapter 3: Objects and Classes Object Oriented Programming

Figure 52: Objects, data, functions, and memory.

In most situations you don’t need to know that there is only one member function for
an entire class. It’s simpler to visualize each object as containing both its own data and
its own member functions. But in some situations, such as in estimating the size of an
executing program, it’s helpful to know what’s happening behind the scenes.

3.4 Defining member function


So far we’ve seen member functions that were defined inside the class definition. This
need not always be the case. Following program shows a member function, add dist(),
that is not defined within the Distance class definition. It is only declared inside the
class, with the statement

void add_dist( Distance, Distance );

This tells the compiler that this function is a member of the class but that it will be
defined outside the class declaration, someplace else in the listing.
Listing 56: Member Function Defined Outside the Class
# include < iostream >
using namespace std ;

class Distance

84
Chapter 3: Objects and Classes Object Oriented Programming

{
private :
int feet ;
float inches ;

public :
void getdist () // get length from user
{
cout << " \ nEnter feet : " ; cin >> feet ;
cout << " Enter inches : " ; cin >> inches ;
}

void showdist () // display distance


{
cout << feet << " \ ' - " << inches << ' \" ';
}

void add_dist ( Distance , Distance ) ;


};

void Distance :: add_dist ( Distance d2 , Distance d3 )


{
inches = d2 . inches + d3 . inches ;
feet = 0; // for possible carry

if ( inches >= 12.0 f )


{
inches -= 12.0 f ;
feet ++;
}
feet += d2 . feet + d3 . feet ;
}

int main ()
{
Distance dist1 , dist2 , dist3 ; // define two lengths
dist1 . getdist () ;
dist2 . getdist () ;
dist3 . add_dist ( dist1 , dist2 ) ;

// display all lengths


cout << " \ ndist1 = " ; dist1 . showdist () ;
cout << " \ ndist2 = " ; dist2 . showdist () ;
cout << " \ ndist3 = " ; dist3 . showdist () ;
cout << endl ;

return 0;
}

85
Chapter 3: Objects and Classes Object Oriented Programming

Figure 53: Scope Resolution Operator

3.5 Defining outer function inline


In C++, a member function can be defined outside the class body using the inline
keyword. This instructs the compiler to attempt to expand the function’s code in place,
potentially reducing function call overhead for small, frequently used functions.

Syntax
inline ReturnType ClassName::FunctionName(parameters) {
// function body
}

Below is a C++ program demonstrating a class Distance with an inline member


function showdist() defined outside the class.
Listing 57: Inline Member Function Defined Outside the Class
# include < iostream >
using namespace std ;

class Distance // English Distance class


{
private :
int feet ;
float inches ;
public :
void setdist ( int ft , float in ) // set Distance to args
{ feet = ft ; inches = in ; }

void getdist () ; // get length from user


void showdist () ; // display distance
};

void Distance :: getdist () {


cout << " \ nEnter feet : " ; cin >> feet ;
cout << " Enter inches : " ; cin >> inches ;
}

// Inline definition outside class


inline void Distance :: showdist () {
cout << feet << " \ ' - " << inches << ' \" ';
}

86
Chapter 3: Objects and Classes Object Oriented Programming

int main ()
{
Distance dist1 , dist2 ; // define two lengths
dist1 . setdist (11 , 6.25) ; // set dist1
dist2 . getdist () ; // get dist2 from user

// display lengths
cout << " \ ndist1 = " ; dist1 . showdist () ;
cout << " \ ndist2 = " ; dist2 . showdist () ;
cout << endl ;
return 0;
}

Output
Enter feet: 5
Enter inches: 8.5
dist1 = 11'-6.25"
dist2 = 5'-8.5"

Note
The function showdist() is defined outside the class with the inline keyword. While
the compiler is not guaranteed to inline the function, it is a request for inlining small,
performance-sensitive functions.

3.6 Objects as member


In C++, a class can contain an object of another class as its data member. This concept
is known as object as a member. It helps in building complex classes by combining
simpler ones.
Example:
Listing 58: Object as a Member
# include < iostream >
using namespace std ;

class Date {
private :
int day , month , year ;
public :
void setDate ( int d , int m , int y ) {
day = d ;
month = m ;
year = y ;
}
void displayDate () {
cout << day << " / " << month << " / " << year ;
}
};

class Employee {

87
Chapter 3: Objects and Classes Object Oriented Programming

private :
int id ;
Date joiningDate ; // Object as member
public :
void setEmployee ( int i , int d , int m , int y ) {
id = i ;
joiningDate . setDate (d , m , y ) ; // Calling function of member
object
}
void showEmployee () {
cout << " ID : " << id << " \ nJoining Date : " ;
joiningDate . displayDate () ; // Calling function of member object
cout << endl ;
}
};

int main () {
Employee emp1 ;
emp1 . setEmployee (101 , 1 , 1 , 2024) ;
emp1 . showEmployee () ;
return 0;
}

Output:

ID: 101
Joining Date: 1/1/2024

In this example, the Employee class contains an object of the Date class as a data
member. We set and display data using member functions of both classes.

3.7 Constructors and destructors


An object can initialize itself when it’s first created, without requiring a separate call
to a member function. This is done using a special member function called a constructor.
A constructor is a member function that is executed automatically whenever an
object is created. It is primarily used to initialize the data members of a class.
Key Features of Constructors:

• Constructor has the same name as the class.

• It has no return type—not even void.

• It is invoked automatically when an object is created.

• Constructors can be overloaded (multiple constructors with different parameter


lists).

3.7.1 Types of Constructor


• Default constructor: A constructor that takes no arguments. It is automatically
provided by the compiler if no constructor is defined. Often we want to initialize
data members in the default (no-argument) constructor as well. If we let the default
constructor do it, we don’t really know what values the data members may be given.

88
Chapter 3: Objects and Classes Object Oriented Programming

Listing 59: Object Representing a Counter Variable


# include < iostream >
using namespace std ;
class Counter
{
private :
unsigned int count ; // count
public :
Counter () : count (0) // Default constructor
{ /* empty body */ }

void inc_count () // increment count


{ count ++; }

int get_count () // return count


{ return count ; }
};
int main ()
{
Counter c1 , c2 ; // define and initialize
cout << " \ nc1 = " << c1 . get_count () ; // display
cout << " \ nc2 = " << c2 . get_count () ;

c1 . inc_count () ; // increment c1
c2 . inc_count () ; // increment c2
c2 . inc_count () ; // increment c2

cout << " \ nc1 = " << c1 . get_count () ; // display again


cout << " \ nc2 = " << c2 . get_count () ;

cout << endl ;


return 0;
}

If multiple members must be initialized, they’re separated by commas.


The result is called the initializer list (sometimes also known as the
member-initialization list).
SomeClass() : m1(7), m2(33), m3(4) // ← initializer list

• Parameterized constructor: A parameterized constructor in C++ is a con-


structor that takes arguments. It allows the initialization of objects with user-
defined values at the time of creation.
Listing 60: Parameterized Constructor in a Counter Class
# include < iostream >
using namespace std ;

class Counter
{
private :
unsigned int count ; // count

public :
// Parameterized constructor
Counter ( unsigned int c ) : count ( c )
{ /* empty body */ }

89
Chapter 3: Objects and Classes Object Oriented Programming

void inc_count () // increment count


{ count ++; }

int get_count () // return count


{ return count ; }
};

int main ()
{
Counter c1 (0) , c2 (5) ; // initialized with different starting
values
cout << " \ nc1 = " << c1 . get_count () ; // display
cout << " \ nc2 = " << c2 . get_count () ;

c1 . inc_count () ; // increment c1
c2 . inc_count () ; // increment c2
c2 . inc_count () ; // increment c2

cout << " \ nc1 = " << c1 . get_count () ; // display again


cout << " \ nc2 = " << c2 . get_count () ;

cout << endl ;


return 0;
}

• Copy constructor: We’ve seen two ways to initialize objects. A no-argument


constructor can initialize data members to constant values, and a multi-argument
constructor can initialize data members to values passed as arguments. Let’s men-
tion another way to initialize an object: you can initialize it with another object
of the same type. Surprisingly, you don’t need to create a special constructor for
this; one is already built into all classes. It’s called the default copy constructor.
It’s a oneargument constructor whose argument is an object of the same class as
the constructor.
But we can define our own copy constructor as shown in below code. Remember
even if we remove the code for copy constructor the code will work completely fine.
Listing 61: Syntax of Copy Constructor
ClassName ( const ClassName & obj ) : variable_name ( obj . variable_name )

Listing 62: ”Copy constructor use”


# include < iostream >
using namespace std ;

class Counter {
private :
unsigned int count ;

public :
// Default constructor
Counter () : count (0) { }

// Parameterized constructor
Counter ( unsigned int c ) : count ( c ) { }

90
Chapter 3: Objects and Classes Object Oriented Programming

// Copy constructor
Counter ( const Counter & other ) : count ( other . count ) {
cout << " Copy constructor called \ n " ;
}

void inc_count () { count ++; }

int get_count () { return count ; }


};

int main () {
Counter c1 (5) ; // parameterized constructor
Counter c2 ( c1 ) ; // direct copy constructor call
Counter c3 = c2 ; // copy initialization

cout << " c1 = " << c1 . get_count () << endl ;


cout << " c2 = " << c2 . get_count () << endl ;
cout << " c3 = " << c3 . get_count () << endl ;

return 0;
}

• Constructor Overloading: Constructor overloading in C++ allows a class to


have multiple constructors with different parameter lists to initialize objects in
various ways.
Listing 63: Overloaded Constructors in Counter Class
class Counter
{
private :
unsigned int count ;

public :
Counter () : count (0) { } // Default
constructor

Counter ( unsigned int c ) : count ( c ) { } //


Parameterized constructor

Counter ( const Counter & other ) : count ( other . count ) // Copy


constructor
{
cout << " Copy constructor called \ n " ;
}
};

Write a C++ class Box that models a three-dimensional box. Implement constructor
overloading by providing:

1. A default constructor that initializes all dimensions (length, width, height) to


1.
2. A parameterized constructor that accepts three double values to initialize the
length, width, and height individually.

91
Chapter 3: Objects and Classes Object Oriented Programming

3. A parameterized constructor that accepts a single double value to initialize


all sides equally (a cube).

Include a member function display() that prints the box dimensions in the format
length x width x height.
Write a main() function to demonstrate the use of all three constructors and display
their initialized dimensions.
Listing 64: Example of Constructor Overloading with Different Parameter Lists
# include < iostream >
using namespace std ;

class Box
{
private :
double length ;
double width ;
double height ;

public :
// Default constructor
Box () : length (1) , width (1) , height (1) { }

// Parameterized constructor for length , width , height


Box ( double l , double w , double h ) : length ( l ) , width ( w ) , height
(h) { }

// Parameterized constructor for cube ( all sides equal )


Box ( double side ) : length ( side ) , width ( side ) , height ( side ) { }

void display ()
{
cout << " Box dimensions : "
<< length << " x " << width << " x " << height << endl
;
}
};

int main ()
{
Box box1 ; // Calls default constructor
Box box2 (3.5 , 4.2 , 5) ; // Calls parameterized constructor
Box box3 (7.0) ; // Calls cube constructor

box1 . display () ;
box2 . display () ;
box3 . display () ;

return 0;
}

3.7.2 Destructors
We’ve seen that a special member function—the constructor—is called automatically
when an object is first created. You might guess that another function is called automat-

92
Chapter 3: Objects and Classes Object Oriented Programming

ically when an object is destroyed. This is indeed the case. Such a function is called a
destructor. A destructor has the same name as the constructor (which is the same as
the class name) but is preceded by a tilde (~).
Listing 65: Constructor and Destructor Example
class Foo
{
private :
int data ;
public :
Foo () : data (0) // constructor ( same name as class )
{ }

~ Foo () // destructor ( same name with tilde )


{ }
};

Like constructors, destructors do not have a return value. They also take no arguments
(the assumption being that there’s only one way to destroy an object). The most common
use of destructors is to deallocate memory that was allocated for the object by the
constructor.
Listing 66: Counter Class Demonstrating Constructor and Destructor
# include < iostream >
using namespace std ;

class Counter
{
private :
unsigned int count ; // count
public :
Counter () : count (0) // constructor
{
cout << " Constructor called . Count initialized to 0. " << endl ;
}

~ Counter () // destructor
{
cout << " Destructor called . Final count was : " << count << endl
;
}

void inc_count () // increment count


{
count ++;
}

int get_count () // return count


{
return count ;
}
};

int main ()
{
Counter c1 , c2 ; // define and initialize
cout << " \ nc1 = " << c1 . get_count () ;

93
Chapter 3: Objects and Classes Object Oriented Programming

cout << " \ nc2 = " << c2 . get_count () ;

c1 . inc_count () ; // increment c1
c2 . inc_count () ; // increment c2
c2 . inc_count () ; // increment c2

cout << " \ nc1 = " << c1 . get_count () ;


cout << " \ nc2 = " << c2 . get_count () ;
cout << endl ;

return 0;
}

In this specific program, the destructor is not strictly necessary because the class Counter
does not allocate any dynamic memory or open resources like files or network sockets.
When the program ends, the objects c1 and c2 go out of scope, and their destructors are
called automatically.
# include < iostream >
# include < cstring >
using namespace std ;

class MyString {
private :
char * str ;

public :
MyString ( const char * input ) {
str = new char [ strlen ( input ) + 1];
strcpy ( str , input ) ;
cout << " Constructor : Allocated \" " << str << " \"\ n " ;
}

~ MyString () {
cout << " Destructor : Deleting \" " << str << " \"\ n " ;
delete [] str ;
}

void display () {
cout << " Stored string : " << str << endl ;
}
};

int main () {
MyString name ( " Ram Thapa " ) ;
name . display () ;
return 0;
}

3.8 Object as function arguments


Consider the code snippets from Listing 56
dist3.add_dist ( dist1 , dist2 ) ;
The two distances to be added, dist1 and dist2, are supplied as arguments to add dist().
The syntax for arguments that are objects is the same as that for arguments that are

94
Chapter 3: Objects and Classes Object Oriented Programming

simple data types such as int: the object name is supplied as the argument. Since
add dist() is a member function of the Distance class, it can access the private data in
any object of class Distance supplied to it as an argument, using names like dist1.inches
and dist2.feet.
Close examination of add dist() emphasizes some important truths about member
functions. A member function is always given access to the object for which it was
called: the object connected to it with the dot operator. But it may be able to access
other objects. In the following statement, what objects can add dist() access?
dist3.add dist(dist1, dist2);
Besides dist3, the object for which it was called, it can also access dist1 and dist2,
because they are supplied as arguments. You might think of dist3 as a sort of phantom
argument; the member function always has access to it, even though it is not supplied
as an argument. That’s what this statement means: “Execute the add dist() member
function of dist3.” When the variables feet and inches are referred to within this
function, they refer to dist3.feet and dist3.inches.
Notice that the result is not returned by the function. The return type of add dist()
is void. The result is stored automatically in the dist3 object. Figure Figure 54 shows
the two distances dist1 and dist2 being added together, with the result stored in dist3.
To summarize, every call to a member function is associated with a particular object
(unless it’s a static function; we’ll get to that later). Using the member names alone
(feet and inches), the function has direct access to all the members, whether private or
public, of that object. It also has indirect access, using the object name and the member
name, connected with the dot operator (dist1.inches or dist2.feet) to other objects
of the same class that are passed as arguments.

Figure 54: Object as argument

3.9 Returning objects from functions


In Listing 56 example, we saw objects being passed as arguments to functions. Now we’ll
see an example of a function that returns an object.

95
Chapter 3: Objects and Classes Object Oriented Programming

Listing 67: Member Function Returning Object


# include < iostream >
using namespace std ;

class Distance
{
private :
int feet ;
float inches ;

public :
void getdist () // get length from user
{
cout << " \ nEnter feet : " ; cin >> feet ;
cout << " Enter inches : " ; cin >> inches ;
}

void showdist () const // display distance


{
cout << feet << " \ ' - " << inches << ' \" ';
}

Distance add_dist ( const Distance & d2 , const Distance & d3 ) const ; //


returns a Distance object
};

Distance Distance :: add_dist ( const Distance & d2 , const Distance & d3 )


const
{
Distance temp ;
temp . inches = d2 . inches + d3 . inches ;
temp . feet = 0; // for possible carry

if ( temp . inches >= 12.0 f )


{
temp . inches -= 12.0 f ;
temp . feet ++;
}
temp . feet += d2 . feet + d3 . feet ;

return temp ;
}

int main ()
{
Distance dist1 , dist2 , dist3 ; // define three distances
dist1 . getdist () ;
dist2 . getdist () ;

dist3 = dist3 . add_dist ( dist1 , dist2 ) ; // call add_dist and assign


returned object to dist3

// display all lengths


cout << " \ ndist1 = " ; dist1 . showdist () ;
cout << " \ ndist2 = " ; dist2 . showdist () ;
cout << " \ ndist3 = " ; dist3 . showdist () ;
cout << endl ;

96
Chapter 3: Objects and Classes Object Oriented Programming

return 0;
}

3.10 Array of objects

Listing 68: Distance Class with Array of Objects


# include < iostream >
using namespace std ;

class Distance
{
private :
int feet ;
float inches ;
public :
void getdist () // get length from user
{
cout << " \ nEnter feet : " ; cin >> feet ;
cout << " Enter inches : " ; cin >> inches ;
}
void showdist () const // display distance
{
cout << feet << " \ ' - " << inches << ' \" ';
}
};

int main ()
{
Distance dist [100]; // array of distances
int n = 0; // count the entries
char ans ; // user response ( ' y ' or 'n ')

cout << endl ;


do {
// get distances from user
cout << " Enter distance number " << n + 1;
dist [ n ++]. getdist () ; // store distance in array
cout << " Enter another ( y / n ) ?: " ;
cin >> ans ;
} while ( ans != 'n ') ; // quit if user types 'n '

for ( int j = 0; j < n ; j ++) // display all distances


{
cout << " \ nDistance number " << j + 1 << " is " ;
dist [ j ]. showdist () ;
}

cout << endl ;


return 0;
}

Sample Output
Enter distance number 1

97
Chapter 3: Objects and Classes Object Oriented Programming

Enter feet: 5
Enter inches: 7.5
Enter another (y/n)?: y
Enter distance number 2
Enter feet: 6
Enter inches: 2.3
Enter another (y/n)?: n

Distance number 1 is 5'-7.5"


Distance number 2 is 6'-2.3"

Figure 55: Array of Objects

3.11 Pointer to objects


Pointers can point to objects as well as to simple data types and arrays. We’ve seen
many examples of objects defined and given a name, in statements like

Distance dist;

where an object called dist is defined to be of the Distance class.


Sometimes, however, we don’t know, at the time that we write the program, how
many objects we want to create. When this is the case, we can use new to create objects
while the program is running.
Listing 69: Accessing Member Functions by Pointer

98
Chapter 3: Objects and Classes Object Oriented Programming

# include < iostream >


using namespace std ;

class Distance // English Distance class


{
private :
int feet ;
float inches ;
public :
void getdist () // get length from user
{
cout << " \ nEnter feet : " ; cin >> feet ;
cout << " Enter inches : " ; cin >> inches ;
}

void showdist () // display distance


{
cout << feet << " \ ' - " << inches << ' \" ';
}
};

int main ()
{
Distance * distptr ; // pointer to Distance
distptr = new Distance ; // points to new Distance object
distptr - > getdist () ; // access object members with -> operator
distptr - > showdist () ;

delete distptr ;
cout << endl ;
return 0;
}

The dot operator requires the identifier on its left to be a variable. Since distptr is a
pointer to a variable, we need another syntax. A concise approach to accessing members of
an object via pointer is furnished by the membership-access operator, which consists
of a hyphen and a greater-than sign (->).

distptr->getdist();

This expression is functionally equivalent to:

(*distptr).getdist();

Here, distptr is a pointer to a Distance object. The -> operator is a shorthand for
dereferencing the pointer and then accessing a member, making it a common and clean
syntax in object-oriented C++ programming when working with pointers to objects.

3.12 Dynamic memory allocation for objects


# include < iostream >
using namespace std ;

class Distance

99
Chapter 3: Objects and Classes Object Oriented Programming

{
private :
int feet ;
float inches ;
public :
void getdist () // get length from user
{
cout << " \ nEnter feet : " ; cin >> feet ;
cout << " Enter inches : " ; cin >> inches ;
}
void showdist () const // display distance
{
cout << feet << " \ ' - " << inches << ' \" ';
}
};

int main ()
{
int n ;
cout << " How many distances do you want to enter ? " ;
cin >> n ;

// dynamically allocate array of Distance objects


Distance * dist = new Distance [ n ];

// input distances
for ( int i = 0; i < n ; i ++) {
cout << " Enter distance number " << i + 1;
dist [ i ]. getdist () ;
}

// display all distances


for ( int i = 0; i < n ; i ++) {
cout << " \ nDistance number " << i + 1 << " is " ;
dist [ i ]. showdist () ;
}

// deallocate memory
delete [] dist ;

cout << endl ;


return 0;
}

3.13 Dynamic constructors


When allocation of memory is done dynamically using the dynamic memory allocator
new in a constructor, it is known as a dynamic constructor. By using this, we can
dynamically initialize the objects.
# include < iostream >
# include < cstring > // For strlen and strcpy

class MyString {
private :
char * str ; // Pointer to dynamically allocated char array

100
Chapter 3: Objects and Classes Object Oriented Programming

public :
// Constructor allocates memory dynamically and copies input string
MyString ( const char * s ) {
str = new char [ strlen ( s ) + 1]; // Allocate memory on heap
strcpy ( str , s ) ; // Copy string content
std :: cout << " Constructor : allocated memory for string \ n " ;
}

// Destructor releases allocated memory


~ MyString () {
delete [] str ;
std :: cout << " Destructor : freed memory \ n " ;
}

// Display the string


void print () const {
std :: cout << str << std :: endl ;
}
};

int main () {
MyString greeting ( " Hello , dynamic memory in constructor ! " ) ;
greeting . print () ;

return 0;
}

3.14 Static data member and static member function


If a data item in a class is declared as static, only one such item is created for the entire
class, no matter how many objects there are. A static data item is useful when all objects
of the same class must share a common item of information. A member variable defined
as static has characteristics similar to a normal static variable: It is visible only within
the class, but its lifetime is the entire program. It continues to exist even if there are no
objects of the class. However, while a normal static variable is used to retain information
between calls to a function, static class member data is used to share information among
the objects of a class.
Listing 70: Static Class Data Example
# include < iostream >
using namespace std ;
class foo
{
private :
static int count ;
public :
foo ()
{
count ++;
}
int getcount ()
{ return count ; }
};

int foo :: count = 0;

101
Chapter 3: Objects and Classes Object Oriented Programming

int main ()
{
foo c1 ;
cout < < c1 . getcount () << endl ;
foo c2 ;
cout < < c2 . getcount () << endl ;
foo c3 ;
cout < < c3 . getcount () << endl ;
return 0;
}

Static class variables are not used as often as ordinary non-static variables, but they are
important in many situations.

Figure 56: Static Variable

Static member data requires an unusual format. Ordinary variables are usually de-
clared (the compiler is told about their name and type) and defined (the compiler sets
aside memory to hold the variable) in the same statement. Static member data, on the
other hand, requires two separate statements. The variable’s declaration appears in the
class definition, but the variable is actually defined outside the class, in much the same
way as a global variable. Why is this two-part approach used? If static member data
were defined inside the class (as it actually was in early versions of C++), it would violate
the idea that a class definition is only a blueprint and does not set aside any memory.

102
Chapter 3: Objects and Classes Object Oriented Programming

Putting the definition of static member data outside the class also serves to emphasize
that the memory space for such data is allocated only once, before the program starts to
execute, and that one static member variable is accessed by an entire class; each object
does not have its own version of the variable, as it would with ordinary member data. In
this way a static member variable is more like a global variable.

• Declared using the static keyword.

• Must be defined outside the class using scope resolution operator.

• Retains its value across all instances.

A static member function can be called using the class name without creating an
object. It can only access static data members.

• Declared with static keyword.

• Cannot access non-static members directly.

Employee Management Imagine a company where we want to:

1. Track the total number of employees.

2. Display employee details.

To achieve this:

• Use a static variable to count the number of employees.

• Use a static function to display the employee count.

Listing 71: Employee Class with Static Members


# include < iostream >
using namespace std ;

class Employee {
private :
string name ;
int id ;
static int count ; // Static variable to count employees

public :
Employee ( string empName , int empId ) {
name = empName ;
id = empId ;
count ++; // Increment when a new employee is created
}

void display () const {


cout << " Name : " << name << " , ID : " << id << endl ;
}

static void showCount () {


cout << " Total Employees : " << count << endl ;
}
};

103
Chapter 3: Objects and Classes Object Oriented Programming

// Definition of static variable outside the class


int Employee :: count = 0;

int main () {
Employee e1 ( " Alice " , 101) ;
Employee e2 ( " Bob " , 102) ;

e1 . display () ;
e2 . display () ;

// Static function called using class name


Employee :: showCount () ;

return 0;
}

5. Output
Name: Alice, ID: 101
Name: Bob, ID: 102
Total Employees: 2

3.15 Constant member functions and constant objects


3.15.1 Constant Member Functions:
A const member function guarantees that it will never modify any of its class’s member
data. A function is made into a constant function by placing the keyword const after
the declarator but before the function body. Member functions that only access (not
modify) the object’s data are good candidates for being marked as const. It guarantees
the function will not change the state of the object.

Syntax Rules
• The keyword const must be placed after the function signature.

• If there is a separate function declaration, const must be added there too.

To avoid raising too many subjects at once, we have, up to now, avoided using const
member functions in the example programs. However, there are many places where const
member functions should be used. For example, in the Distance class (used in several
programs), the showdist() member function could be made const because it doesn’t
(or certainly shouldn’t!) modify any of the data in the object for which it was called. Its
only role is to display the data. Marking such functions as const not only improves code
clarity but also helps catch potential logic errors during compilation. It enforces the rule
that accessor or display functions must not change the object’s internal state.
Listing 72: Using const with member functions and arguments
# include < iostream >
using namespace std ;

104
Chapter 3: Objects and Classes Object Oriented Programming

class Distance // English Distance class


{
private :
int feet ;
float inches ;

public :
// constructor ( no args )
Distance () : feet (0) , inches (0.0) { }

// constructor ( two args )


Distance ( int ft , float in ) : feet ( ft ) , inches ( in ) { }

void getdist () // get length from user


{
cout << " \ nEnter feet : " ; cin >> feet ;
cout << " Enter inches : " ; cin >> inches ;
}

void showdist () const // display distance


{
cout << feet << " \ ' - " << inches << ' \" ';
}

Distance add_dist ( const Distance &) const ; // add


};

// add this distance to d2 , return the sum


Distance Distance :: add_dist ( const Distance & d2 ) const
{
Distance temp ; // temporary variable

// feet = 0; // ERROR : can 't modify this


// d2 . feet = 0; // ERROR : can 't modify d2

temp . inches = inches + d2 . inches ; // add the inches

if ( temp . inches >= 12.0) // if total exceeds 12.0 ,


{
temp . inches -= 12.0; // decrease inches by 12.0
temp . feet = 1; // increase feet by 1
}

temp . feet += feet + d2 . feet ; // add the feet


return temp ;
}

int main ()
{
Distance dist1 , dist3 ; // define two lengths
Distance dist2 (11 , 6.25) ; // define , initialize dist2

dist1 . getdist () ; // get dist1 from user


dist3 = dist1 . add_dist ( dist2 ) ; // dist3 = dist1 + dist2

// display all lengths


cout << " \ ndist1 = " ; dist1 . showdist () ;

105
Chapter 3: Objects and Classes Object Oriented Programming

cout << " \ ndist2 = " ; dist2 . showdist () ;


cout << " \ ndist3 = " ; dist3 . showdist () ;
cout << endl ;

return 0;
}

3.16 Friend functions and friend classes


The concepts of encapsulation and data hiding dictate that nonmember functions should
not be able to access an object’s private or protected data. The policy is, if you’re not a
member, you can’t get in. However, there are situations where such rigid discrimination
leads to considerable inconvenience. Imagine that you want a function to operate on
objects of two different classes. Perhaps the function will take objects of the two classes
as arguments, and operate on their private data.
Listing 73: Friend Function Accessing Private Members of Two Classes
# include < iostream >
using namespace std ;

class beta ; // Needed for frifunc declaration

class alpha {
private :
int data ;
public :
alpha () : data (3) { } // No - arg constructor
friend int frifunc ( alpha , beta ) ; // Friend function
};

class beta {
private :
int data ;
public :
beta () : data (7) { } // No - arg constructor
friend int frifunc ( alpha , beta ) ; // Friend function
};

int frifunc ( alpha a , beta b ) { // Function definition


return ( a . data + b . data ) ;
}

int main () {
alpha aa ;
beta bb ;
cout << frifunc ( aa , bb ) << endl ; // Call the function
return 0;
}

In this program, the two classes are alpha and beta. The constructors in these classes
initialize their single data items to fixed values (3 in alpha and 7 in beta). We want the
function frifunc() to have access to both of these private data members, so we make it
a friend function. It’s declared with the friend keyword in both classes:
friend int frifunc(alpha, beta);

106
Chapter 3: Objects and Classes Object Oriented Programming

This declaration can be placed anywhere in the class; it doesn’t matter whether it goes
in the public or the private section. An object of each class is passed as an argument to
the function frifunc(), and it accesses the private data member of both classes through
these arguments. The function doesn’t do much: it adds the data items and returns the
sum. The main() program calls this function and prints the result.
A minor point: Remember that a class can’t be referred to until it has been declared.
Class beta is referred to in the declaration of the function frifunc() in class alpha, so
beta must be declared before alpha. Hence the declaration:

class beta;

at the beginning of the program.


In C++, private data members of a class cannot be accessed directly outside the class.
However, there are two common ways to allow operations like modifying or computing
on private data:

• By using a public member function of the class itself.

• By using a friend function, which is a non-member function that has access to


the class’s private data.

The following examples demonstrate how to square a private integer member using
both methods:
Listing 74: Squaring a Private Variable without Using Friend Function
# include < iostream >
using namespace std ;

class Number {
private :
int value ;

public :
Number ( int v ) : value ( v ) {}

void square () {
value = value * value ;
}

void display () {
cout << " Value : " << value << endl ;
}
};

int main () {
Number num (5) ;
num . square () ; // Squaring using member function
num . display () ; // Output : Value : 25
return 0;
}

Listing 75: Squaring a Private Variable Using Friend Function


# include < iostream >

107
Chapter 3: Objects and Classes Object Oriented Programming

using namespace std ;

class Number {
private :
int value ;

public :
Number ( int v ) : value ( v ) {}

friend void square ( Number & n ) ; // Friend function declaration

void display () {
cout << " Value : " << value << endl ;
}
};

// Friend function definition


void square ( Number & n ) {
n . value = n . value * n . value ;
}

int main () {
Number num (5) ;
square ( num ) ; // Squaring using friend function
num . display () ; // Output : Value : 25
return 0;
}

As seen in the first example, the square operation is performed using a public member
function, keeping everything encapsulated within the class.
In the second example, a friend function is used. This allows the squaring operation
to be performed by a non-member function that still has access to the class’s private
data.
While friend functions break the encapsulation slightly, they are useful when two or
more classes or external functions need to work closely with a class’s private members.
friend Classes The member functions of a class can all be made friend at the same
time by declaring the entire class as a friend of another class. This allows every member
function of the friend class to access the private and protected members of the class
granting the friendship.
Listing 76: Friend Class Accessing Private Members
# include < iostream >
using namespace std ;

class alpha {
private :
int data1 ;
public :
alpha () : data1 (99) { } // constructor
friend class beta ; // beta is a friend class
};

class beta {
public :
// All member functions of beta can access private members of alpha
void func1 ( alpha a ) { cout << " \ ndata1 = " << a . data1 ; }

108
Chapter 3: Objects and Classes Object Oriented Programming

void func2 ( alpha a ) { cout << " \ ndata1 = " << a . data1 ; }
};

int main () {
alpha a ;
beta b ;
b . func1 ( a ) ;
b . func2 ( a ) ;
cout << endl ;
return 0;
}

In class alpha, the entire class beta is proclaimed a friend. Now all the member functions
of beta can access the private data of alpha (in this program, the single data item data1).
Note that in the friend declaration we specify that beta is a class using the class keyword:

friend class beta;

We could have also declared beta to be a class before the alpha class specifier, as in
previous examples:

class beta;

and then, within alpha, referred to beta without the class keyword:

friend beta;

109
Chapter 4: Operator Overloading Object Oriented Programming

Chapter 4: Operator Overloading


4.1 Overloadable and non- overloadable operators
Operator overloading is one of the most exciting features of object-oriented programming.
It can transform complex, obscure program listings into intuitively obvious ones. For
example, statements like:
d3.addobjects(d1, d2);
or the similar but equally obscure:
d3 = d1.addobjects(d2);
can be changed to the much more readable:
d3 = d1 + d2;
The rather forbidding term operator overloading refers to giving the normal C++
operators, such as +, *, <=, and +=, additional meanings when they are applied to user-
defined data types.
Normally, a statement like:
a = b + c;
works only with basic types such as int and float, and attempting to apply it when
a, b, and c are objects of a user-defined class will cause complaints from the compiler.
However, using overloading, you can make this statement legal even when a, b, and c are
user-defined types.
In effect, operator overloading gives you the opportunity to redefine the C++ lan-
guage. If you find yourself limited by the way the C++ operators work, you can change
them to do whatever you want. By using classes to create new kinds of variables, and
operator overloading to create new definitions for operators, you can extend C++ to
be, in many ways, a new language of your own design. In C++, most operators can
be overloaded to work with user-defined types, allowing intuitive syntax and improved
readability. However, there are a few exceptions that cannot be overloaded.

Overloadable Operators
The following operators can be overloaded in C++:

• Arithmetic Operators: +, -, *, /, %

• Relational Operators: ==, !=, <, >, <=, >=

• Logical Operators: &&, ||, !

• Bitwise Operators: &, |, ^, ~, <<, >>

• Assignment Operators: =, +=, -=, *=, /=, %=, etc.

• Increment/Decrement Operators: ++, --

• Subscript Operator: []

110
Chapter 4: Operator Overloading Object Oriented Programming

• Function Call Operator: ()

• Dereference and Member Access Operators: *, ->

• Input/Output Operators: >>, <<

• Other Operators: new, delete, new[], delete[]

Non-Overloadable Operators
Some of the operators that cannot be overloaded:

• Scope Resolution Operator: ::

• Member Access Operator: .

• Ternary Conditional Operator: ?:

• sizeof Operator

4.2 Syntax of operator overloading


The general syntax for operator overloading is:

return_type class_name::operator<op>(argument_list) {
// operator definition
}

- operator<op> is the keyword operator followed by the symbol of the operator to


overload (e.g., +, -, ==). - return type is the type of value the overloaded operator
returns. - argument list depends on whether the operator is a member or non-member
function.

4.3 Operator overloading using member operator functions


Member Function:

class ClassName {
public:
ReturnType operator<op>(ClassName obj);
};

4.4 Operator overloading using non member functions


Non-Member (Friend) Function:

class ClassName {
friend ReturnType operator<op>(ClassName a, ClassName b);
};

111
Chapter 4: Operator Overloading Object Oriented Programming

4.5 Unary operator overloading


Let’s start off by overloading a unary operator.
In the COUNTER example from Chapter 3, “Objects and Classes,” we created a class
Counter to keep track of a count. Objects of this class were incremented by calling a
member function:

c1.inc_count();

This approach was functional, but the code could be made more readable and intuitive
by using the built-in increment operator ++ instead:

++c1;

All experienced C++ (and C) programmers would immediately understand that this
expression increments c1, making the code more natural and expressive.
Operator overloading allows us to define custom behavior for the ++ operator when
used with user-defined types such as our Counter class. This improves both code clarity
and maintainability.
The following program demonstrates how to overload the prefix increment operator
++ to increment a counter variable:

// increment counter variable with ++ operator


#include <iostream>
using namespace std;

class Counter {
private:
unsigned int count; // count
public:
Counter() : count(0) { } // constructor

unsigned int get_count() { // return count


return count;
}

void operator++() { // overload prefix ++


++count;
}
};

int main() {
Counter c1, c2; // define and initialize

cout << "\nc1 = " << c1.get_count(); // display


cout << "\nc2 = " << c2.get_count();

++c1; // increment c1
++c2; // increment c2

112
Chapter 4: Operator Overloading Object Oriented Programming

++c2; // increment c2 again

cout << "\nc1 = " << c1.get_count(); // display again


cout << "\nc2 = " << c2.get_count() << endl;

return 0;
}
Output:
c1 = 0
c2 = 0
c1 = 1
c2 = 2
The keyword operator is used to overload the ++ operator in the following declarator:
void operator++();
The return type (in this case, void) comes first, followed by the keyword operator,
then the operator itself (++), and finally the argument list enclosed in parentheses (which
is empty for the prefix version).
This declarator syntax tells the compiler to call this member function whenever the
++ operator is encountered, provided the operand (i.e., the variable operated on by ++)
is of type Counter.
We learned in “Functions Overloading,” that the only way the compiler can distin-
guish between overloaded functions is by examining the data types and number of their
arguments. In the same way, the compiler distinguishes between overloaded operators by
looking at the data type of their operands.
If the operand is a built-in type such as int, as in:
++intvar;
then the compiler uses its built-in routine to increment an int. However, if the
operand is a Counter object, the compiler knows to invoke the user-defined operator++()
function instead.

Figure 57: ++ Operator Overloading

113
Chapter 4: Operator Overloading Object Oriented Programming

To make it possible to use our homemade operator++() in assignment expressions,


we must provide a way for it to return a value. This example shows how to overload the
prefix increment operator ++ so that it returns a value, allowing expressions like c2 =
++c1; to work correctly.
// increment counter variable with ++ operator , return value
# include < iostream >
using namespace std ;

class Counter {
private :
unsigned int count ; // count
public :
Counter () : count (0) { } // constructor

unsigned int get_count () { // return count


return count ;
}

Counter operator ++() { // overload prefix ++ with return value


++ count ; // increment count
Counter temp ; // make a temporary Counter
temp . count = count ; // assign incremented value
return temp ; // return the copy
}
};

int main () {
Counter c1 , c2 ; // c1 = 0 , c2 = 0

cout << " \ nc1 = " << c1 . get_count () ; // display


cout << " \ nc2 = " << c2 . get_count () ;

++ c1 ; // c1 = 1
c2 = ++ c1 ; // c1 = 2 , c2 = 2

cout << " \ nc1 = " << c1 . get_count () ; // display again


cout << " \ nc2 = " << c2 . get_count () << endl ;

return 0;
}

Output:
c1 = 0
c2 = 0
c1 = 2
c2 = 2
Here the operator++() function creates a new object of type Counter, called temp, to
use as a return value. It increments the count data in its own object as before, then
creates the new temp object and assigns count in the new object the same value as in its
own object. Finally, it returns the temp object.
In above we created a temporary object of type Counter, named temp, whose sole
purpose was to provide a return value for the ++ operator. This required three statements:
Counter temp; % make a temporary Counter object

114
Chapter 4: Operator Overloading Object Oriented Programming

temp.count = count; % give it same value as this object


return temp; % return it

There are more convenient ways to return temporary objects from functions and over-
loaded operators.
Listing 77: Counter class with overloaded prefix increment operator
# include < iostream >
using namespace std ;

class Counter
{
private :
unsigned int count ; // count

public :
Counter () : count (0) { } // constructor : no args
Counter ( int c ) : count ( c ) { } // constructor : one arg

unsigned int get_count () { // return count


return count ;
}

Counter operator ++() // prefix increment operator


{
++ count ; // increment count
return Counter ( count ) ; // return unnamed temporary
object
}
};

int main ()
{
Counter c1 , c2 ; // c1 =0 , c2 =0 initially
cout << " \ nc1 = " << c1 . get_count () ; // display c1 count
cout << " \ nc2 = " << c2 . get_count () ; // display c2 count

++ c1 ; // c1 =1
c2 = ++ c1 ; // c1 =2 , c2 =2

cout << " \ nc1 = " << c1 . get_count () ; // display c1 count


cout << " \ nc2 = " << c2 . get_count () << endl ; // display c2 count

return 0;
}

In this program, a single statement

return Counter(count);

does what all three statements did in previous program. This statement creates an
object of type Counter. This object has no name; it won’t be around long enough to need
one. This unnamed object is initialized to the value provided by the argument count.
But wait: Doesn’t this require a constructor that takes one argument? It does, and to
make this statement work, we sneakily inserted just such a constructor into the member
function list in COUNTPP3:

115
Chapter 4: Operator Overloading Object Oriented Programming

Counter(int c) : count(c) // constructor, one argument


{ }

Once the unnamed object is initialized to the value of count, it can then be returned.
Listing 78: Overloading prefix and postfix ++ operators
# include < iostream >
using namespace std ;

class Counter
{
private :
unsigned int count ; // count

public :
Counter () : count (0) { } // constructor : no args
Counter ( int c ) : count ( c ) { } // constructor : one arg

unsigned int get_count () const { // return current count


return count ;
}

// Prefix increment
Counter operator ++() {
return Counter (++ count ) ; // increment first , then return
temporary
}

// Postfix increment
Counter operator ++( int ) {
return Counter ( count ++) ; // return temporary , then
increment
}
};

int main ()
{
Counter c1 , c2 ; // c1 = 0 , c2 = 0
cout << " \ nc1 = " << c1 . get_count () ;
cout << " \ nc2 = " << c2 . get_count () ;

++ c1 ; // c1 = 1
c2 = ++ c1 ; // c1 = 2 , c2 = 2 ( prefix )
cout << " \ nc1 = " << c1 . get_count () ;
cout << " \ nc2 = " << c2 . get_count () ;

c2 = c1 ++; // c2 = 2 , c1 = 3 ( postfix )
cout << " \ nc1 = " << c1 . get_count () ;
cout << " \ nc2 = " << c2 . get_count () << endl ;

return 0;
}

Now there are two different declarators for overloading the ++ operator. The one
we’ve seen before, for prefix notation, is:

Counter operator++()

116
Chapter 4: Operator Overloading Object Oriented Programming

The new one, for postfix notation, is:

Counter operator++(int)

The only difference is the int in the parentheses. This int isn’t really an argument,
and it doesn’t mean integer. It’s simply a signal to the compiler to create the postfix
version of the operator. The designers of C++ are fond of recycling existing operators
and keywords to play multiple roles, and int is the one they chose to indicate postfix.
(Well, can you think of a better syntax?)

Program Output
c1=0
c2=0
c1=2
c2=2
c1=3
c2=2

4.6 Binary operator overloading


In the Distance program in Chapter 3, two English Distance objects were added using
a member function add dist() as:

dist3.add_dist(dist1, dist2);

By overloading the + operator, this expression can be simplified to:

dist3 = dist1 + dist2;

Below is the listing for the Distance program which demonstrates this:
Listing 79: Overloaded + operator for Distance
# include < iostream >
using namespace std ;

class Distance
{
private :
int feet ;
float inches ;

public :
Distance () : feet (0) , inches (0.0) { } // no - arg
constructor
Distance ( int ft , float in ) : feet ( ft ) , inches ( in ) { } // two - arg
constructor

void getdist () {
cout << " \ nEnter feet : " ; cin >> feet ;
cout << " Enter inches : " ; cin >> inches ;
}

117
Chapter 4: Operator Overloading Object Oriented Programming

void showdist () const {


cout << feet << " \ ' - " << inches << " \" " ;
}

Distance operator +( Distance ) const ; // overload + operator


};

// Add this distance to d2 and return result


Distance Distance :: operator +( Distance d2 ) const {
int f = feet + d2 . feet ;
float i = inches + d2 . inches ;

if ( i >= 12.0) {
i -= 12.0;
f ++;
}
return Distance (f , i ) ;
}

int main ()
{
Distance dist1 , dist3 , dist4 ;
dist1 . getdist () ; // get input for dist1
Distance dist2 (11 , 6.25) ; // initialize dist2

dist3 = dist1 + dist2 ; // use overloaded +


dist4 = dist1 + dist2 + dist3 ; // chain addition

cout << " dist1 = "; dist1 . showdist () ; cout << endl ;
cout << " dist2 = "; dist2 . showdist () ; cout << endl ;
cout << " dist3 = "; dist3 . showdist () ; cout << endl ;
cout << " dist4 = "; dist4 . showdist () ; cout << endl ;

return 0;
}

Sample Output
Enter feet: 10
Enter inches: 6.5
dist1 = 10'-6.5"
dist2 = 11'-6.25"
dist3 = 22'-0.75"
dist4 = 44'-1.5"

To demonstrate that the result of an addition can itself be used in another addition
(as well as an assignment), the following statement adds three distances:

dist4 = dist1 + dist2 + dist3;

This uses the associativity of the + operator and constructs intermediate unnamed
temporary objects. The key declaration in the class is:

Distance operator+(Distance);

118
Chapter 4: Operator Overloading Object Oriented Programming

This function returns a Distance object and takes one argument of type Distance.
In the statement:

dist3 = dist1 + dist2;

The left-hand operand dist1 is the object that calls the operator+ function. The
right-hand operand dist2 is passed as an argument. The function returns a new tempo-
rary Distance object containing the sum, which is then assigned to dist3.
This structure allows chaining:
dist4 = dist1 + dist2 + dist3;
is treated as:
temp = dist1 + dist2;
dist4 = temp + dist3;

Figure 58: Overload Binary Operator

In the operator+() function, the left operand is accessed directly—since this is the
object of which the operator is a member—using feet and inches. The right operand is
accessed as the function’s argument, as d2.feet and d2.inches. We can generalize and
say that an overloaded operator always requires one less argument than its number of
operands, since one operand is the object of which the operator is a member. That’s why
unary operators require no arguments.(This rule does not apply to friend functions and
operators)
The + operator cannot be used to concatenate C-style strings. That is, the following
expression is invalid in standard C++:

str3 = str1 + str2;

119
Chapter 4: Operator Overloading Object Oriented Programming

where str1, str2, and str3 are C-string variables (i.e., arrays of type char), as
in "cat" plus "bird" equals "catbird". However, if we use a user-defined String
class—like the one shown in the String program in Chapter 3—we can overload the +
operator to enable such concatenation.
This functionality is also provided by the Standard C++ std::string class, but
implementing it ourselves using a custom class makes the underlying mechanism more
transparent. Overloading the + operator to perform concatenation—something that isn’t
numerically additive—is a good example of how C++ enables redefining the meaning of
built-in operators to support user-defined behavior.
Such operator overloading enhances the usability of the class and provides syntactic
convenience, allowing us to write intuitive expressions like:

String s1("cat");
String s2("bird");
String s3 = s1 + s2; // yields "catbird"

This approach makes the String class behave more like built-in types, thereby con-
tributing to more readable and expressive code. The following program demonstrates
how the + operator can be overloaded to concatenate two user-defined String objects.
// overloaded + operator concatenates strings
# include < iostream >
using namespace std ;
# include < string .h > // for strcpy () , strcat ()
# include < stdlib .h > // for exit ()

class String // user - defined string type


{
private :
enum { SZ = 80 }; // size of String objects
char str [ SZ ]; // holds a string

public :
String () // constructor , no args
{ strcpy ( str , " " ) ; }

String ( char s []) // constructor , one arg


{ strcpy ( str , s ) ; }

void display () const // display the String


{ cout << str ; }

String operator + ( String ss ) const // add Strings


{
String temp ; // make a temporary String
if ( strlen ( str ) + strlen ( ss . str ) < SZ )
{
strcpy ( temp . str , str ) ; // copy this string to temp
strcat ( temp . str , ss . str ) ; // add the argument string
}
else
{
cout << " \ nString overflow " ;
exit (1) ;

120
Chapter 4: Operator Overloading Object Oriented Programming

}
return temp ; // return temp String
}
};

int main ()
{
String s1 = " \ nMerry Christmas ! " ; // uses constructor 2
String s2 = " Happy new year ! " ; // uses constructor 2
String s3 ; // uses constructor 1

s1 . display () ; // display strings


s2 . display () ;
s3 . display () ;

s3 = s1 + s2 ; // add s2 to s1 , assign to s3
s3 . display () ; // display s3

cout << endl ;


return 0;
}

Program Output:

Merry Christmas! Happy new year!

This example illustrates how a custom String class can make use of operator over-
loading to support intuitive operations like concatenation using the + symbol—something
that isn’t directly possible with C-style strings.
Comparison Operators:
Listing 80: Overloaded comparison Operator to Compare Distances
# include < iostream >
using namespace std ;

class Distance // English Distance class


{
private :
int feet ;
float inches ;
public :
Distance () : feet (0) , inches (0.0) { } // constructor ( no args )
Distance ( int ft , float in ) : feet ( ft ) , inches ( in ) { } //
constructor ( two args )

void getdist () // get length from user


{
cout << " \ nEnter feet : " ; cin >> feet ;
cout << " Enter inches : " ; cin >> inches ;
}

void showdist () const // display distance


{
cout << feet << " '-" << inches << " \" " ;
}

121
Chapter 4: Operator Overloading Object Oriented Programming

bool operator < ( Distance ) const ; // compare distances


};

// compare this distance with d2


bool Distance :: operator < ( Distance d2 ) const
{
float bf1 = feet + inches / 12;
float bf2 = d2 . feet + d2 . inches / 12;
return ( bf1 < bf2 ) ? true : false ;
}

int main ()
{
Distance dist1 ; // define Distance dist1
dist1 . getdist () ; // get dist1 from user
Distance dist2 (6 , 2.5) ; // define and initialize dist2

// display distances
cout << " \ ndist1 = " ; dist1 . showdist () ;
cout << " \ ndist2 = " ; dist2 . showdist () ;

if ( dist1 < dist2 ) // overloaded '<' operator


cout << " \ ndist1 is less than dist2 " ;
else
cout << " \ ndist1 is greater than ( or equal to ) dist2 " ;

cout << endl ;


return 0;
}

Listing 81: Overloaded += Assignment Operator in Distance Class


# include < iostream >
using namespace std ;

class Distance // English Distance class


{
private :
int feet ;
float inches ;
public :
Distance () : feet (0) , inches (0.0) // constructor ( no args )
{ }
Distance ( int ft , float in ) : feet ( ft ) , inches ( in ) // constructor (
two args )
{ }
void getdist () // get length from user
{
cout << " \ nEnter feet : " ; cin >> feet ;
cout << " Enter inches : " ; cin >> inches ;
}
void showdist () const // display distance
{ cout << feet << " \ ' - " << inches << ' \" '; }

void operator += ( Distance ) ; // overloaded += operator


};

// add distance to this one

122
Chapter 4: Operator Overloading Object Oriented Programming

void Distance :: operator += ( Distance d2 )


{
feet += d2 . feet ; // add the feet
inches += d2 . inches ; // add the inches
if ( inches >= 12.0) // if total exceeds 12.0 ,
{ // then decrease inches
inches -= 12.0; // by 12.0 and
feet ++; // increase feet
}
}

int main ()
{
Distance dist1 ; // define dist1
dist1 . getdist () ; // get dist1 from user
cout << " \ ndist1 = " ; dist1 . showdist () ;

Distance dist2 (11 , 6.25) ; // define , initialize dist2


cout << " \ ndist2 = " ; dist2 . showdist () ;

dist1 += dist2 ; // dist1 = dist1 + dist2


cout << " \ nAfter addition , " ;
cout << " \ ndist1 = " ; dist1 . showdist () ;
cout << endl ;
return 0;
}

Overloaded [] Operator Returning by Reference To access a safe array using


the same subscript operator [] that’s used for normal C++ arrays, we can overload the
subscript operator in the SafeArray class. This makes the class behave like a built-in
array when accessed with indices.
However, since this operator is commonly used on the left side of the equal sign
(i.e., for assignment), the overloaded function must return a reference to the element.
Returning by reference allows the assignment to modify the actual array element.
Listing 82: Safe Array with Overloaded Subscript Operator
# include < iostream >
using namespace std ;
# include < process .h > // for exit ()

const int LIMIT = 100; // array size

class safearay
{
private :
int arr [ LIMIT ];
public :
int & operator []( int n ) // return by reference
{
if ( n < 0 || n >= LIMIT )
{
cout << " \ nIndex out of bounds " ;
exit (1) ;
}
return arr [ n ];
}
};

123
Chapter 4: Operator Overloading Object Oriented Programming

int main ()
{
safearay sa1 ;

// Insert elements
for ( int j = 0; j < LIMIT ; j ++)
sa1 [ j ] = j * 10; // * left * side of equal sign

// Display elements
for ( int j = 0; j < LIMIT ; j ++)
{
int temp = sa1 [ j ]; // * right * side of equal sign
cout << " Element " << j << " is " << temp << endl ;
}

return 0;
}

Explanation
In this program we can use natural subscript expressions:

• sa1[j] = j * 10; — to assign values (input)

• temp = sa1[j]; — to retrieve values (output)

The overloaded operator:


int & operator []( int n )

returns a reference to an element in the internal array. This allows the array to be used
like a regular C++ array but with built-in bounds checking, improving safety without
sacrificing syntax.

Note: Returning by reference is crucial when the operator is used on the left-hand
side of an assignment statement, as it allows direct modification of the array element.
overloading the Assignment Operator
# include < iostream >
using namespace std ;

class alpha {
private :
int data ;

public :
alpha () { } // no - arg constructor
alpha ( int d ) { data = d ; } // one - arg constructor

void display () {
cout << data ;
}

alpha operator = ( const alpha & a ) { // overloaded = operator


data = a . data ;

124
Chapter 4: Operator Overloading Object Oriented Programming

cout << " \ nAssignment operator invoked " ;


return alpha ( data ) ; // return a copy
}
};

int main () {
alpha a1 (37) ; // initialize a1
alpha a2 ; // uninitialized
a2 = a1 ; // invokes overloaded =

cout << " \ na2 = " ; a2 . display () ; // prints a2 's value

alpha a3 = a2 ; // uses copy constructor


cout << " \ na3 = " ; a3 . display () ; // prints a3 's value

cout << endl ;


return 0;
}

Output
Assignment operator invoked
a2 =37
a3 =37

• alpha operator=(const alpha& a) is the overloaded assignment operator. It


copies the value of data from a.

• The line a2 = a1; calls this function, printing a message and assigning data.

• The statement alpha a3 = a2; does not invoke the assignment operator — it calls
the copy constructor (default or compiler-generated).

• Note: Returning by value instead of by reference here is acceptable for this simple
class but not efficient or typical in real-world scenarios.

When we want to keep operator logic external or allow operations where the left-hand
operand is not an object of the class (e.g., 5 + obj), we can use a non-member function.
To allow a non-member function to access private members of the class, we declare
it as a friend of the class.
In this example, we overload the prefix ++ operator using a non-member function.
// co unter_ nonmem ber . cpp
# include < iostream >
using namespace std ;

class Counter
{
private :
unsigned int count ; // count

public :
Counter () : count (0) { } // constructor : no args

125
Chapter 4: Operator Overloading Object Oriented Programming

Counter ( int c ) : count ( c ) { } // constructor : one arg

unsigned int get_count () const { // return count


return count ;
}

// Declare non - member function as friend


friend Counter operator ++( Counter & c ) ;
};

// Define the prefix ++ operator as a non - member function


Counter operator ++( Counter & c )
{
++ c . count ; // increment count directly
return Counter ( c . count ) ; // return an unnamed temporary
object
}

int main ()
{
Counter c1 , c2 ; // c1 = 0 , c2 = 0
cout << " \ nc1 = " << c1 . get_count () ; // display c1
cout << " \ nc2 = " << c2 . get_count () ; // display c2

++ c1 ; // c1 = 1
c2 = ++ c1 ; // c1 = 2 , c2 = 2

cout << " \ nc1 = " << c1 . get_count () ; // display c1


cout << " \ nc2 = " << c2 . get_count () << endl ; // display c2

return 0;
}

Listing 83: Distance Addition using Friend Function


# include < iostream >
using namespace std ;

class Distance {
private :
int feet ;
float inches ;

public :
Distance () : feet (0) , inches (0.0) { }
Distance ( int ft , float in ) : feet ( ft ) , inches ( in ) { }

void getdist () {
cout << " \ nEnter feet : " ; cin >> feet ;
cout << " Enter inches : " ; cin >> inches ;
}

void showdist () const {


cout << feet << " '-" << inches << " \" " ;
}

// Friend function declaration


friend Distance operator +( const Distance & , const Distance &) ;

126
Chapter 4: Operator Overloading Object Oriented Programming

};

// Friend function definition


Distance operator +( const Distance & d1 , const Distance & d2 ) {
int f = d1 . feet + d2 . feet ;
float i = d1 . inches + d2 . inches ;

if ( i >= 12.0) {
i -= 12.0;
f ++;
}

return Distance (f , i ) ;
}

int main () {
Distance dist1 , dist3 , dist4 ;
dist1 . getdist () ;
Distance dist2 (11 , 6.25) ;

dist3 = dist1 + dist2 ;


dist4 = dist1 + dist2 + dist3 ;

cout << " dist1 = "; dist1 . showdist () ; cout << endl ;
cout << " dist2 = "; dist2 . showdist () ; cout << endl ;
cout << " dist3 = "; dist3 . showdist () ; cout << endl ;
cout << " dist4 = "; dist4 . showdist () ; cout << endl ;

return 0;
}

In the given program, the binary + operator is overloaded using a friend function.

Function Definition
Distance operator+(const Distance& d1, const Distance& d2) {
int f = d1.feet + d2.feet;
float i = d1.inches + d2.inches;

if (i >= 12.0) {
i -= 12.0;
f++;
}

return Distance(f, i);


}

• The function receives two Distance objects by constant reference.


• It directly accesses the private members d1.feet, d2.inches, etc., because it is a
declared friend.
• It adds the values, adjusts inches if necessary, and returns a new Distance object.
The table below compares the syntax and behavior of unary and binary operator over-
loading using member and non-member (friend) functions:

127
Chapter 4: Operator Overloading Object Oriented Programming

Operator Type Member Function Friend (Non-Member)


Syntax Function Syntax
Unary Operator ReturnType friend ReturnType
(e.g., ++) operator++(); operator++(Class&);
Takes no argument Takes one argument (the
object)
Binary Operator ReturnType friend ReturnType
(e.g., +) operator+(const Class& operator+(const Class&,
obj); const Class&);
Takes one argument Takes two arguments (both
(right-hand operand) operands)
When to Prefer Unary or modifying the Symmetric binary
current object operations, external logic,
or mixed-type operands

Note:
• Member functions implicitly use the left-hand operand as the object (’*this’).
• Friend functions require explicit parameters for both operands but can access pri-
vate members.
In C++, overloading the + operator using both a member function and a friend
function allows flexible arithmetic-like expressions involving user-defined types. This
example demonstrates how to support both obj + 5 and 5 + obj with a Number class.
Listing 84: Operator Overloading to Support obj + 5 and 5 + obj
# include < iostream >
using namespace std ;

class Number {
private :
int value ;

public :
Number ( int v = 0) : value ( v ) {}

void display () const {


cout << " Value = " << value << endl ;
}

// Member function : obj + int


Number operator +( int x ) const {
return Number ( value + x ) ;
}

// Friend function : int + obj


friend Number operator +( int x , const Number & n ) ;
};

// Friend function : enables 5 + obj


Number operator +( int x , const Number & n ) {
return Number ( x + n . value ) ;

128
Chapter 4: Operator Overloading Object Oriented Programming

int main () {
Number obj (10) ;
Number res1 = obj + 5; // Calls member function
Number res2 = 5 + obj ; // Calls friend function

res1 . display () ; // Output : Value = 15


res2 . display () ; // Output : Value = 15

return 0;
}

• Member Function: The statement obj + 5 calls the member function operator+(int).
The object obj is the left-hand operand, and 5 is passed as the argument.

• Friend Function: The statement 5 + obj is not valid with a member function
because the left-hand operand (5) is not an object. To support this, we define a
non-member friend function that takes the integer first and the object second.

• Flexibility: This dual overloading allows user-defined objects to participate in


arithmetic expressions just like primitive types.

Conclusion: To support both obj + 5 and 5 + obj, we must overload the + operator
using:
• A member function for obj + 5

• A friend (non-member) function for 5 + obj


Overloading >> and << Operators in C++
Listing 85: Overloading insertion and extraction operators using friend functions
# include < iostream >
using namespace std ;

class Point {
private :
int x , y ;
public :
Point () : x (0) , y (0) {}

// Friend function for output


friend ostream & operator < <( ostream & out , Point & p ) ;

// Friend function for input


friend istream & operator > >( istream & in , Point & p ) ;
};

// Overload << operator


ostream & operator < <( ostream & out , const Point & p ) {
out << " ( " << p . x << " , " << p . y << " ) " ;
return out ;
}

// Overload >> operator

129
Chapter 4: Operator Overloading Object Oriented Programming

istream & operator > >( istream & in , Point & p ) {


cout << " Enter x and y : " ;
in >> p . x >> p . y ;
return in ;
}

int main () {
Point p ;
cin >> p ;
cout << " Point : " << p << endl ;
return 0;
}

• Friend functions allow us to access private members of the class.

• operator<< takes an ostream and a const Point& and returns a reference to the
stream.

• operator>> takes an istream and a non-const Point& to modify the object.

• In main(), input is taken using cin >> p, and output is shown using cout << p.

Sample Output

Console Output
Enter x and y: 3 4
Point: (3, 4)

Overloading the input (>>) and output (<<) operators using friend functions allows
for seamless and readable I/O of class objects, just like built-in types.

4.7 Type conversion between objects


We’ll first review how the compiler handles the conversion of basic types, which it does
automatically. Then we’ll explore several situations where the compiler doesn’t handle
things automatically and we need to tell it what to do. These include conversions between
basic types and user-defined types, and conversions between different user-defined types.

4.7.1 Conversions Between Basic Types


When we write a statement like:

intvar = floatvar;

where intvar is of type int and floatvar is of type float, we are assuming that the
compiler will automatically invoke a special routine to convert the value of floatvar,
which is expressed in floating-point format, to an integer format so that it can be assigned
to intvar.

There are, of course, many such type conversions supported in C++, such as:

• float to double

130
Chapter 4: Operator Overloading Object Oriented Programming

• char to float

• int to double

• double to int
Each such conversion has its own rules, precision implications, and performance
cost. The compiler performs automatic type conversion (also known as implicit conver-
sion) only when there is no risk of data loss, such as converting an int to a float.
However, when converting from a float to an int, the compiler may truncate the
decimal part, potentially resulting in data loss. This is why such conversions must be
well-understood by the programmer.

Some important points about conversions:


• Implicit conversions follow a hierarchy of data types (e.g., int → float → double).

• Explicit conversions, or type casting, allow manual control over how data types
are converted.

• Certain conversions may lead to undefined behavior if not used properly..


Sometimes, we want to force the compiler to convert one data type to another. To
do this, we use the cast operator. For instance, to convert a float to an int, we can
write:
intvar = static_cast < int >( floatvar ) ;

This is known as explicit type conversion or type casting. The use of static cast<int>()
makes it clear in the source code that the conversion from float to int is intentional.

4.7.2 Conversions Between Objects and Basic Types


When we want to convert between user-defined data types and basic types, we cannot rely
on built-in conversion routines, since the compiler does not know anything about user-
defined types except what we explicitly specify. Instead, we must write these conversion
routines ourselves. The following example demonstrates conversion between a basic type
(int) and a user-defined object (Box). It shows both:

• Conversion from int to Box using a constructor.

• Conversion from Box to int using a conversion operator.


Listing 86: Conversion Operator Syntax
operator < type >() {
// return value of < type >
}

Listing 87: Simple conversion between int and object


# include < iostream >
using namespace std ;

class Box {

131
Chapter 4: Operator Overloading Object Oriented Programming

int length ;

public :
// Constructor to convert int to Box
Box ( int l ) {
length = l ;
}

// Conversion operator to convert Box to int


operator int () {
return length ;
}

void show () {
cout << " Length = " << length << endl ;
}
};

int main () {
Box b1 = 10; // int to Box conversion
b1 . show () ; // Output : Length = 10

int x = b1 ; // Box to int conversion


cout << " x = " << x << endl ; // Output : x = 10

return 0;
}

• Box b1 = 10; invokes the Box(int) constructor, converting the integer 10 into a
Box object.

• int x = b1; invokes the conversion operator operator int(), converting the
Box object into an int This operator can be called with an explicit cast x =
static cast<int>(b1);.

• This shows how user-defined types can participate in assignments and expressions
involving built-in types using conversion mechanisms.

Our next example shows how to convert between a basic type and a user-defined type.
In this example, the user-defined type is (surprise!) the English Distance class from
previous examples, and the basic type is float, which we use to represent meters, a unit
of length in the metric measurement system.
Listing 88: Distance class with conversion between meters (float) and feet/inches
# include < iostream >
using namespace std ;

class Distance {
private :
const float MTF ; // meters to feet conversion factor
int feet ;
float inches ;

public :
// No - arg constructor

132
Chapter 4: Operator Overloading Object Oriented Programming

Distance () : feet (0) , inches (0.0) , MTF (3.280833 F ) { }

// One - arg constructor : converts meters to Distance


Distance ( float meters ) : MTF (3.280833 F ) {
float fltfeet = MTF * meters ; // convert meters to float feet
feet = static_cast < int >( fltfeer ) ; // integer part
is feet
inches = 12 * ( fltfeet - feet ) ; // remainder converted to
inches
}

// Two - arg constructor


Distance ( int ft , float in ) : feet ( ft ) , inches ( in ) , MTF (3.280833 F ) {
}

void getdist () {
cout << " \ nEnter feet : " ; cin >> feet ;
cout << " Enter inches : " ; cin >> inches ;
}

void showdist () const {


cout << feet << " \ ' - " << inches << " \" " ;
}

// Conversion operator : Distance -> float ( meters )


operator float () const {
float fracfeet = inches / 12; // convert inches to
fraction feet
fracfeet += static_cast < float >( feet ) ; // add feet
return fracfeet / MTF ; // convert feet to
meters
}
};

int main () {
float mtrs ;
Distance dist1 = 2.35 F ; // uses 1 - arg constructor to convert
meters to Distance
cout << " \ ndist1 = " ; dist1 . showdist () ;

mtrs = static_cast < float >( dist1 ) ; // uses conversion operator


Distance -> float
cout << " \ ndist1 = " << mtrs << " meters \ n " ;

Distance dist2 (5 , 10.25) ; // uses 2 - arg constructor


mtrs = dist2 ; // also uses conversion operator
cout << " \ ndist2 = " << mtrs << " meters \ n " ;

// dist2 = mtrs ; // error : assignment from float to Distance not


defined

return 0;
}

133
Chapter 4: Operator Overloading Object Oriented Programming

4.7.3 Conversions Between Objects of Different Classes


Conversions between two user-defined types can be accomplished using the same tech-
niques as conversions between basic types and user-defined types. Specifically, there are
two approaches:

1. Using a one-argument constructor in the destination class.

2. Using a conversion operator in the source class.

Consider the following assignment:


objecta = objectb;
Here,
• objecta is an instance of class A (the destination class).

• objectb is an instance of class B (the source class).

1. Conversion Constructor in the Destination Class:


# include < iostream >
# include < cmath >
using namespace std ;

class Rectangle {
float x , y ;
public :
Rectangle ( float a , float b ) : x ( a ) , y ( b ) {}
float getX () const { return x; }
float getY () const { return y; }
void show () {
cout << " Rectangle : x = " << x << " , y = " << y << endl ;
}
};

class Polar {
float radius , angle ; // angle in degrees
public :
Polar () : radius (0) , angle (0) {}

// Conversion constructor uses public getters


Polar ( const Rectangle & rect ) {
radius = sqrt ( rect . getX () * rect . getX () + rect . getY () *
rect . getY () ) ;
angle = atan2 ( rect . getY () , rect . getX () ) * 180 / M_PI ;
}

void show () {
cout << " Polar : radius = " << radius << " , angle = " <<
angle << " degrees " << endl ;
}
};

int main () {
Rectangle rect (3.0 , 4.0) ;

134
Chapter 4: Operator Overloading Object Oriented Programming

rect . show () ;

// Conversion using constructor


Polar p = rect ;
p . show () ;

return 0;
}

In the main() function of the first program, we define an object of type Rectangle,
named rect, with given x and y coordinates. We also define an object of type
Polar, named p, and initialize it using the statement:
Polar p = rect ;

Since these objects belong to different classes, a conversion must take place. In this
example, the constructor:
Polar ( const Rectangle & rect )

performs the conversion. It is a member of the Polar class and accepts a Rectangle
object as a parameter. The constructor accesses the rectangle’s dimensions via
public getter functions, calculates the radius and angle (in degrees), and initializes
the new Polar object accordingly.

Sample Interaction:

Rectangle: x = 3.0, y = 4.0


Polar: radius = 5, angle = 53.1301 degrees

The values x = 3.0 and y = 4.0 form a right triangle with hypotenuse (radius) 5,
and an angle of approximately 53.13 degrees, confirming the conversion is correct.

2. Conversion Operator in the Source Class


# include < iostream >
# include < cmath >
using namespace std ;

class Polar {
float radius , angle ;
public :
Polar () : radius (0) , angle (0) {}
Polar ( float r , float a ) : radius ( r ) , angle ( a ) {}

void show () {
cout << " Polar : radius = " << radius << " , angle = " <<
angle << " degrees " << endl ;
}
};

class Rectangle {
float x , y ;
public :
Rectangle ( float a , float b ) : x ( a ) , y ( b ) {}

135
Chapter 4: Operator Overloading Object Oriented Programming

float getX () const { return x ; }


float getY () const { return y ; }

// Conversion operator uses public getters


operator Polar () const {
float r = sqrt ( x * x + y * y ) ;
float a = atan2 (y , x ) * 180 / M_PI ;
return Polar (r , a ) ;
}

void show () {
cout << " Rectangle : x = " << x << " , y = " << y << endl ;
}
};

int main () {
Rectangle rect (3.0 , 4.0) ;
rect . show () ;

// Conversion using conversion operator


Polar p = rect ;
p . show () ;

return 0;
}

In the second program, we again define a Rectangle object, rect, and a Polar
object, p. This time, we use the statement:
Polar p = rect ;

Here, the conversion is implemented via the following conversion operator:


operator Polar () const ;

This operator is a member of the Rectangle class. It uses the values of x and y
(accessed directly within the class) to compute the radius and angle, constructs a
temporary Polar object with these values, and returns it.

Sample Interaction:

Rectangle: x = 6.0, y = 8.0


Polar: radius = 10, angle = 53.1301 degrees

This result is again based on a right triangle (6-8-10), confirming accurate and
meaningful conversion between the two user-defined types using operator overload-
ing. Both techniques allow seamless conversion between user-defined types:

• Use a constructor in the destination class when you want the conversion
logic in the receiving object.
• Use a conversion operator in the source class when you want the source
object to define how it should be converted.

136
Chapter 4: Operator Overloading Object Oriented Programming

4.8 Explicit Constructors in C++


In C++, constructors with a single parameter can be used by the compiler for **implicit
type conversions**. To prevent such implicit conversions, we use the keyword explicit.

• Use explicit to avoid accidental object creation from a single value.

• It makes the constructor call more predictable and controlled.

explicit ClassName(Type parameter);

Listing 89: Demonstrating explicit constructor


# include < iostream >
using namespace std ;

class Distance {
private :
int meter ;
public :
// Explicit constructor
explicit Distance ( int m ) {
meter = m ;
cout << " Constructor called \ n " ;
}

void display () {
cout << " Meter = " << meter << endl ;
}
};

int main () {
Distance d1 (5) ; // OK : Direct initialization
// Distance d2 = 10; // Error : Implicit conversion not allowed
d1 . display () ;
return 0;
}

Console Output
Constructor called
Meter = 5

• Distance d1(5); works because it’s a direct call.

• Distance d2 = 10; would normally be allowed for a non-explicit constructor, but


here it’s prohibited, which avoids **unintended type conversions**.

explicit constructors add safety to object creation, especially when dealing with single-
argument constructors, by preventing automatic conversions that may lead to bugs.

137
Chapter 5: Inheritance Object Oriented Programming

Chapter 5: Inheritance
5.1 Base class and derived class
Inheritance is probably the most powerful feature of object-oriented programming, af-
ter classes themselves. Inheritance is the process of creating new classes, called derived
classes, from existing or base classes. The derived class inherits all the capabilities of the
base class but can add embellishments and refinements of its own. The base class is un-
changed by this process. Inheritance is an essential part of object-oriented programming

Figure 59: Inheritance

(OOP). Its big payoff is that it permits code reusability. Once a base class is written
and debugged, it need not be touched again but, using inheritance, can nevertheless be
adapted to work in different situations. Reusing existing code saves time and money and
increases a program’s reliability.
Inheritance can also help in the original conceptualization of a programming problem,
and in the overall design of the program. An important result of reusability is the ease
of distributing class libraries. A programmer can use a class created by another person
or company, and, without modifying it, derive other classes from it that are suited to
particular situations.
Let’s suppose that we have worked long and hard to make the Counter class operate

138
Chapter 5: Inheritance Object Oriented Programming

just the way we want, and we’re pleased with the results—except for one thing. We really
need a way to decrement the count. Perhaps we’re counting people entering a bank,
and we want to increment the count when they come in and decrement it when they go
out, so that the count represents the number of people in the bank at any moment.
We could insert a decrement routine directly into the source code of the Counter
class. However, there are several reasons that we might not want to do this. First, the
Counter class works very well and has undergone many hours of testing and debugging.
(Of course that’s an exaggeration in this case, but it would be true in a larger and more
complex class.) If we start fooling around with the source code for Counter, the testing
process will need to be carried out again, and of course we may foul something up and
spend hours debugging code that worked fine before we modified it.
In some situations there might be another reason for not modifying the Counter class:
We might not have access to its source code, especially if it was distributed as part of a
class library.
To avoid these problems, we can use inheritance to create a new class based on
Counter, without modifying Counter itself. Here’s the listing for COUNTEN, which includes
a new class, CountDn, that adds a decrement operator to the Counter class:
Listing 90: Inheritance with Counter Class
# include < iostream >
using namespace std ;

class Counter // base class


{
protected :
unsigned int count ; // count

public :
Counter () : count (0) {} // no - arg constructor
Counter ( int c ) : count ( c ) {} // 1 - arg constructor

unsigned int get_count () const { // return count


return count ;
}

Counter operator ++() { // prefix increment


return Counter (++ count ) ;
}
};

class CountDn : public Counter // derived class


{
public :
Counter operator - -() { // prefix decrement
return Counter ( - - count ) ;
}
};

int main ()
{
CountDn c1 ; // c1 of class CountDn
cout << " \ nc1 = " << c1 . get_count () ; // display c1
++ c1 ; ++ c1 ; ++ c1 ; // increment c1 , 3 times
cout << " \ nc1 = " << c1 . get_count () ; // display it
-- c1 ; -- c1 ; // decrement c1 , twice

139
Chapter 5: Inheritance Object Oriented Programming

cout << " \ nc1 = " << c1 . get_count () ; // display it


cout << endl ;
return 0;
}

Following the Counter class in the listing is the specification for a new class, CountDn.
This class incorporates a new function, operator--(), which decrements the count.
However—and here’s the key point—the new CountDn class inherits all the features of the
Counter class. CountDn doesn’t need a constructor or the get count() or operator++()
functions, because these already exist in Counter.
The first line of CountDn specifies that it is derived from Counter:

class CountDn : public Counter

Here we use a single colon (not the double colon used for the scope resolution operator),
followed by the keyword public and the name of the base class Counter. This sets up
the relationship between the classes. This line says that CountDn is derived from the base
class Counter.

5.2 Protected access specifier


The data in the classes we’ve looked at so far, including count in the Counter class in
the earlier program, have used the protected access specifier. Let’s first review what
we know about the access specifiers private and public. A member function of a class
can always access class members, whether they are public or private. But an object
declared externally can only invoke (using the dot operator, for example) public members
of the class. It’s not allowed to use private members.
This is all we need to know if we don’t use inheritance. With inheritance, however,
there is a whole raft of additional possibilities. The question that concerns us at the
moment is, can member functions of the derived class access members of the base class?
In other words, can operator--() in CountDn access count in Counter? The answer is
that member functions can access members of the base class if the members are public,
or if they are protected. They can’t access private members.
A protected member, on the other hand, can be accessed by member functions in
its own class or—and here’s the key—in any class derived from its own class. It can’t be
accessed from functions outside these classes, such as main(). This is just what we want.

140
Chapter 5: Inheritance Object Oriented Programming

Figure 60: Access Specifier

Figure 61: Inheritance with Protected

The moral is that if you are writing a class that you suspect might be used, at any
point in the future, as a base class for other classes, then any member data that the
derived classes might need to access should be made protected rather than private.
This ensures that the class is “inheritance ready.”

141
Chapter 5: Inheritance Object Oriented Programming

Table 12: Inheritance and Accessibility

Access Specifier Own Class Derived Class Objects Outside Class


public yes yes yes
protected yes yes no
private yes no no

5.3 Derived class declaration


5.4 Derived Class Declaration
A derived class is a class that inherits from a base class, allowing it to reuse and extend
the functionality of the base class. In C++, a derived class is declared by specifying the
base class after a colon (‘:‘) following the derived class name.

Syntax:
class DerivedClassName : visibility_mode BaseClassName {
// additional members and functions
};
Here, visibility mode is usually public, protected, or private, and it controls
the accessibility of the base class members in the derived class.

Example: Consider the classes Counter and Counterdn where Counterdn is derived
from Counter:

class Counter // base class


{
protected:
unsigned int count; // count

public:
Counter() : count(0) {} // no-arg constructor
Counter(int c) : count(c) {} // 1-arg constructor

unsigned int get_count() const { // return count


return count;
}

Counter operator++() { // prefix increment


return Counter(++count);
}
};

class CountDn : public Counter // derived class


{
public:

142
Chapter 5: Inheritance Object Oriented Programming

Counter operator--() { // prefix decrement


return Counter(--count);
}
};

In this example:

• Counterdn inherits from Counter using public inheritance.

• This means all public and protected members of Counter are accessible in Counterdn.

• The derived class Counterdn adds a new operator operator--() to decrement


count.

5.5 Is a relation and Has a relation


In object-oriented programming, understanding the relationships between classes is cru-
cial. Two fundamental types of relationships are the Is-a and Has-a relations.

Is-a Relation The Is-a relationship represents inheritance. It means that a derived
class is a specialized type of the base class. This relationship is modeled using inheritance
in C++.

• If class Derived inherits from class Base, then Derived is a Base.

• The derived class inherits attributes and behaviors (data members and member
functions) from the base class.

• Example: Counterdn is a Counter.

Listing 91: Is-a Relation Example


class Counter {
protected :
unsigned int count ;
public :
Counter () : count (0) {}
unsigned int get_count () const { return count ; }
void increment () { ++ count ; }
};

class Counterdn : public Counter { // Counterdn is a Counter


public :
void decrement () { -- count ; }
};

Has-a Relation The Has-a relationship represents composition or aggregation. It


means that a class contains another class as a member, showing ownership or usage.

• If class A contains an object of class B, then A has a B.

• This relationship models a “part-of” or “contains” association.

143
Chapter 5: Inheritance Object Oriented Programming

• Example: A Car has a Engine.

Listing 92: Has-a Relation Example


class Engine {
public :
void start () { /* start engine */ }
};

class Car {
private :
Engine engine ; // Car has an Engine
public :
void startCar () { engine . start () ; }
};

5.6 Public, protected and private inheritance


In C++, inheritance can be specified as public, protected, or private. These access
specifiers control how the members of the base class are inherited by the derived class
and their accessibility to outside code.

Public Inheritance

• Public and protected members of the base class keep their access levels in the
derived class.

• Public members remain public.

• Protected members remain protected.

• Private members are never accessible directly by derived classes.

Protected Inheritance

• Public and protected members of the base class become protected members in the
derived class.

• Private members remain inaccessible.

• This restricts access to base class members from outside the derived class.

Private Inheritance

• Public and protected members of the base class become private members in the
derived class.

• Private members remain inaccessible.

• This means even the formerly public members are hidden from outside access
through the derived class.

144
Chapter 5: Inheritance Object Oriented Programming

Summary Table

Inheritance Type Base Public Base Protected Base Private


Public Public Protected Not inherited
Protected Protected Protected Not inherited
Private Private Private Not inherited

5.7 Member overriding


Member overriding allows a derived class to redefine a function with the same name and
parameters as one in its base class. Below are three cases demonstrating how this works
in C++.

1. Without Overriding (Separate Functions) Here, the base and derived classes
define different function names: getPerson(), getEmployee(), etc. There is no overrid-
ing.
Listing 93: No Overriding – Separate Functions
# include < iostream >
using namespace std ;

class Person {
protected :
string name ;
int age ;
public :
void getPerson () {
cout << " Enter name : " ;
cin >> name ;
cout << " Enter age : " ;
cin >> age ;
}
void showPerson () {
cout << " Name : " << name << " \ nAge : " << age << endl ;
}
};

class Employee : public Person {


private :
int empID ;
float salary ;
public :
void getEmployee () {
cout << " Enter employee ID : " ;
cin >> empID ;
cout << " Enter salary : " ;
cin >> salary ;
}
void showEmployee () {
cout << " Employee ID : " << empID << " \ nSalary : " << salary <<
endl ;
}
};

145
Chapter 5: Inheritance Object Oriented Programming

int main () {
Employee e ;
e . getPerson () ;
e . getEmployee () ;
e . showPerson () ;
e . showEmployee () ;
}

2. With Member Overriding (Same Function Names) Here, both classes define
functions with the same name (getData(), showDetails()), and the derived version
overrides the base version. Note: no virtual is used.
Listing 94: Member Overriding – Same Function Names
# include < iostream >
using namespace std ;

class Person {
protected :
string name ;
int age ;
public :
void getData () {
cout << " Enter name : " ;
cin >> name ;
cout << " Enter age : " ;
cin >> age ;
}
void showDetails () {
cout << " Name : " << name << " \ nAge : " << age << endl ;
}
};

class Employee : public Person {


private :
int empID ;
float salary ;
public :
void getData () {
cout << " Enter name : " ;
cin >> name ;
cout << " Enter age : " ;
cin >> age ;
cout << " Enter employee ID : " ;
cin >> empID ;
cout << " Enter salary : " ;
cin >> salary ;
}
void showDetails () {
cout << " Name : " << name << " \ nAge : " << age ;
cout << " \ nEmployee ID : " << empID << " \ nSalary : " << salary <<
endl ;
}
};

int main () {

146
Chapter 5: Inheritance Object Oriented Programming

Employee e ;
e . getData () ; // Calls Employee :: getData ()
e . showDetails () ; // Calls Employee :: showDetails ()
}

3. Using Scope Resolution to Access Base Class Function In this example, the
derived class uses Person::getData() to explicitly call the base class version from within
its own function.
Listing 95: Calling Base Class Method using Scope Resolution
# include < iostream >
using namespace std ;

class Person {
protected :
string name ;
int age ;
public :
void getData () {
cout << " Enter name : " ;
cin >> name ;
cout << " Enter age : " ;
cin >> age ;
}
};

class Employee : public Person {


private :
int empID ;
float salary ;
public :
void getData () {
Person :: getData () ; // Call base class method
cout << " Enter employee ID : " ;
cin >> empID ;
cout << " Enter salary : " ;
cin >> salary ;
}
void showDetails () {
cout << " Name : " << name << " \ nAge : " << age ;
cout << " \ nEmployee ID : " << empID << " \ nSalary : " << salary <<
endl ;
}
};

int main () {
Employee e ;
e . getData () ;
e . showDetails () ;
}

Conclusion:

• Without overriding, different function names are used in base and derived classes.

147
Chapter 5: Inheritance Object Oriented Programming

• With overriding, same function names exist, and derived versions are preferred.

• Base class functions can be accessed using scope resolution syntax like BaseClass::function().

Note: Here’s the rule: When the same function exists in both the base class and the
derived class, the function in the derived class will be executed. (This is true of objects
of the derived class. Objects of the base class don’t know anything about the derived
class and will always use the base class functions.) We say that the derived class function
overrides the base class function.

5.8 Forms of inheritance


5.8.1 Single Inheritance
In this type of inheritance one derived class inherits from only one base class. It is the
simplest form of Inheritance.

Person

Employee

Example: In above program Employee inherits from Person(Employee is derived from


Person).

5.8.2 Multiple Inheritance


In this type of inheritance a single derived class may inherit from two or more than two
base classes.
Listing 96: Syntax of Multiple Inheritance
class base_classname1 {
// members of base_classname1
};

class base_classname2 {
// members of base_classname2
};

class derive d_cla ssname : visibility_mode base_classname1 ,


visibility_mode base_classname2 ,
... {
// members of de rived_ classn ame
};

148
Chapter 5: Inheritance Object Oriented Programming

Example of Multiple Inheritance In this example, the Employee class is derived


from two base classes: Person and Department. This demonstrates multiple inheritance
in C++.

Person Department

Employee

Listing 97: Multiple Inheritance Example


# include < iostream >
using namespace std ;

class Person {
protected :
string name ;
int age ;
public :
void getPersonData () {
cout << " Enter name : " ;
cin >> name ;
cout << " Enter age : " ;
cin >> age ;
}
void showPersonData () {
cout << " Name : " << name << " \ nAge : " << age << endl ;
}
};

class Department {
protected :
string deptName ;
public :
void get Depart mentD ata () {
cout << " Enter department name : " ;
cin >> deptName ;
}
void s ho wD ep ar tm en tD at a () {
cout << " Department : " << deptName << endl ;
}
};

class Employee : public Person , public Department {


private :
int empID ;
float salary ;
public :
void getEmployeeData () {
getPersonData () ;
getD epartm entDat a () ;
cout << " Enter employee ID : " ;
cin >> empID ;

149
Chapter 5: Inheritance Object Oriented Programming

cout << " Enter salary : " ;


cin >> salary ;
}

void showEmployeeData () {
showPersonData () ;
sh ow De pa rt me nt Da ta () ;
cout << " Employee ID : " << empID << " \ nSalary : " << salary <<
endl ;
}
};

int main () {
Employee e ;
e . getEmployeeData () ;
e . showEmployeeData () ;
}

Explanation:

• Employee inherits from both Person and Department using public inheritance.

• It combines attributes from both base classes along with its own.

• Functions from both base classes are used in the derived class to gather and display
full details.

Ambiguity in Multiple Inheritance


Listing 98: Ambiguity in Multiple Inheritance
# include < iostream >
using namespace std ;

class Person {
protected :
string name ;
int age ;
public :
void getData () {
cout << " Enter name : " ;
cin >> name ;
cout << " Enter age : " ;
cin >> age ;
}
void showData () {
cout << " Name : " << name << " \ nAge : " << age << endl ;
}
};

class Department {
protected :
string deptName ;
public :
void getData () {
cout << " Enter department name : " ;
cin >> deptName ;

150
Chapter 5: Inheritance Object Oriented Programming

}
void showData () {
cout << " Department : " << deptName << endl ;
}
};

class Employee : public Person , public Department {


private :
int empID ;
float salary ;
public :
void getEmployee () {
cout << " Enter employee ID : " ;
cin >> empID ;
cout << " Enter salary : " ;
cin >> salary ;
}

void showEmployee () {
cout << " Employee ID : " << empID << " \ nSalary : " << salary <<
endl ;
}
};

int main () {
Employee e ;
// e . getData () ; // Ambiguous call

e . Person :: getData () ; // Resolving ambiguity


e . Department :: getData () ; // Resolving ambiguity
e . getEmployee () ;

e . Person :: showData () ;
e . Department :: showData () ;
e . showEmployee () ;
return 0;
}

Ambiguity in Multiple Inheritance


Both Person and Department classes define methods with the same name: getData()
and showData(). When accessed from the Employee class object, this creates ambiguity
since the compiler cannot decide which version to call.

Solution: Using Scope Resolution Operator


To resolve this ambiguity, we use the scope resolution operator to specify the exact base
class whose method we want to invoke:

• e.Person::getData(); — Calls getData() from Person

• e.Department::getData(); — Calls getData() from Department

This ensures that the correct base class version of the function is invoked and ambi-
guity is eliminated.

151
Chapter 5: Inheritance Object Oriented Programming

5.8.3 Multilevel Inheritance


Multilevel inheritance is a type of inheritance where a derived class inherits from another
derived class, creating a chain of inheritance levels.

Person

Employee

Manager

Listing 99: C++ Program Demonstrating Multilevel Inheritance


# include < iostream >
using namespace std ;

class Person {
protected :
string name ;
int age ;
public :
void getPersonData () {
cout << " Enter name : " ;
cin >> name ;
cout << " Enter age : " ;
cin >> age ;
}
void showPersonData () {
cout << " Name : " << name << " \ nAge : " << age << endl ;
}
};

class Employee : public Person {


protected :
int empID ;
float salary ;
public :
void getEmployeeData () {
getPersonData () ;
cout << " Enter employee ID : " ;
cin >> empID ;
cout << " Enter salary : " ;
cin >> salary ;
}
void showEmployeeData () {
showPersonData () ;
cout << " Employee ID : " << empID << " \ nSalary : " << salary <<
endl ;

152
Chapter 5: Inheritance Object Oriented Programming

}
};

class Manager : public Employee {


private :
string deptName ;
public :
void getManagerData () {
getEmployeeData () ;
cout << " Enter department name : " ;
cin >> deptName ;
}
void showManagerData () {
showEmployeeData () ;
cout << " Department : " << deptName << endl ;
}
};

int main () {
Manager m ;
m . getManagerData () ;
m . showManagerData () ;
return 0;
}

5.8.4 Hierarchical Inheritance


Hierarchical inheritance is a type of inheritance where multiple derived classes inherit
from a single base class.

Person

Employee Manager

Listing 100: C++ Program Demonstrating Hierarchical Inheritance


# include < iostream >
using namespace std ;

class Person {
protected :
string name ;
int age ;
public :
void getPersonData () {
cout << " Enter name : " ;
cin >> name ;
cout << " Enter age : " ;
cin >> age ;
}

153
Chapter 5: Inheritance Object Oriented Programming

void showPersonData () {
cout << " Name : " << name << " \ nAge : " << age << endl ;
}
};

class Employee : public Person {


protected :
int empID ;
float salary ;
public :
void getEmployeeData () {
getPersonData () ;
cout << " Enter employee ID : " ;
cin >> empID ;
cout << " Enter salary : " ;
cin >> salary ;
}
void showEmployeeData () {
showPersonData () ;
cout << " Employee ID : " << empID << " \ nSalary : " << salary <<
endl ;
}
};

class Manager : public Person {


private :
string deptName ;
public :
void getManagerData () {
getPersonData () ;
cout << " Enter department name : " ;
cin >> deptName ;
}
void showManagerData () {
showPersonData () ;
cout << " Department : " << deptName << endl ;
}
};

int main () {
Employee e ;
Manager m ;

e . getEmployeeData () ;
e . showEmployeeData () ;

cout << " \ n " ;

m . getManagerData () ;
m . showManagerData () ;

return 0;
}

154
Chapter 5: Inheritance Object Oriented Programming

5.8.5 Hybrid Inheritance


Hybrid inheritance is a combination of two or more types of inheritance, such as multilevel
and multiple inheritance, forming a complex hierarchy.

Person Department

Employee

Manager

Listing 101: C++ Program Demonstrating Hybrid Inheritance


# include < iostream >
using namespace std ;

class Person {
protected :
string name ;
int age ;
public :
void getPersonData () {
cout << " Enter name : " ;
cin >> name ;
cout << " Enter age : " ;
cin >> age ;
}
void showPersonData () {
cout << " Name : " << name << " \ nAge : " << age << endl ;
}
};

class Department {
protected :
string deptName ;
public :
void get Depart mentD ata () {
cout << " Enter department name : " ;
cin >> deptName ;
}
void s ho wD ep ar tm en tD at a () {
cout << " Department : " << deptName << endl ;
}
};

class Employee : public Person {


protected :
int empID ;

155
Chapter 5: Inheritance Object Oriented Programming

float salary ;
public :
void getEmployeeData () {
getPersonData () ;
cout << " Enter employee ID : " ;
cin >> empID ;
cout << " Enter salary : " ;
cin >> salary ;
}
void showEmployeeData () {
showPersonData () ;
cout << " Employee ID : " << empID << " \ nSalary : " << salary <<
endl ;
}
};

class Manager : public Employee , public Department {


public :
void getManagerData () {
getEmployeeData () ;
getD epartm entDat a () ;
}
void showManagerData () {
showEmployeeData () ;
sh ow De pa rt me nt Da ta () ;
}
};

int main () {
Manager m ;
m . getManagerData () ;
m . showManagerData () ;
return 0;
}

5.8.6 Multipath Inheritance


Multipath inheritance occurs when a derived class inherits from two classes that both
inherit from the same base class, forming multiple paths to the base — resolved using
virtual inheritance.

5.9 Constructors in derived class


When an object of a derived class is created, the constructors of its base classes are called
automatically before the constructor of the derived class.

5.9.1 Constructor in Single Inheritance


In single inheritance, the constructor of the base class is called first, followed by the
constructor of the derived class.
Listing 102: Constructor Order in Single Inheritance
# include < iostream >
using namespace std ;

156
Chapter 5: Inheritance Object Oriented Programming

class A {
public :
A () {
cout << " Base class A constructor called " << endl ;
}
};

class B : public A {
public :
B () {
cout << " Derived class B constructor called " << endl ;
}
};

int main () {
B obj ;
return 0;
}

Output:
Base class A constructor called
Derived class B constructor called
When object obj of class B is created, the constructor of A is called first automatically,
then the constructor of B.

5.9.2 Constructor in Multiple Inheritance


In multiple inheritance, the constructors of the base classes are called in the order they
are listed in the derived class declaration, and then the constructor of the derived class
is called.
Listing 103: Constructor Order in Multiple Inheritance
# include < iostream >
using namespace std ;

class A {
public :
A () {
cout << " Base class A constructor called " << endl ;
}
};

class B {
public :
B () {
cout << " Base class B constructor called " << endl ;
}
};

class C : public A , public B {


public :
C () {
cout << " Derived class C constructor called " << endl ;
}
};

157
Chapter 5: Inheritance Object Oriented Programming

int main () {
C obj ;
return 0;
}

Output:

Base class A constructor called


Base class B constructor called
Derived class C constructor called

The base classes A and B are listed in that order in the declaration of C. Therefore,
constructors of A and B are called in that sequence before the constructor of C.

5.9.3 Passing Arguments to Base Class Constructor


When the base class has a parameterized constructor, the derived class must pass the
required arguments to the base class constructor using an initialization list.
Listing 104: Passing Arguments to Base Class Constructor
# include < iostream >
using namespace std ;

class A {
public :
A ( int x ) {
cout << " Base class A constructor called with x = " << x <<
endl ;
}
};

class B : public A {
public :
B ( int y , int x ) : A ( x ) {
cout << " Derived class B constructor called with y = " << y <<
endl ;
}
};

int main () {
B obj (5 ,4) ;
return 0;
}

Base class A constructor called with x = 4


Derived class B constructor called with y = 5

• The base class A has a constructor that requires an integer argument.

• The derived class B passes the value of x to A’s constructor using an initialization
list: B(int y, int x): A(x).

• In main(), an object of class B is created with values (5, 4).

158
Chapter 5: Inheritance Object Oriented Programming

• First, the base class constructor A(4) is executed.

• Then, the derived class constructor B(5, 4) is executed.

Derived class constructors must use initialization lists to explicitly call base class
constructors when they are parameterized.
In multiple inheritance, the derived class must use an initialization list to pass argu-
ments to all base class constructors. The base class constructors are called in the order
of their appearance in the class declaration — not the order in the initialization list.
Listing 105: Multiple Inheritance with Constructor Arguments
# include < iostream >
using namespace std ;

class A {
public :
A ( int x ) {
cout << " Base class A constructor called with x = " << x <<
endl ;
}
};

class B {
public :
B ( int y ) {
cout << " Base class B constructor called with y = " << y <<
endl ;
}
};

class C : public A , public B {


public :
C ( int p , int q , int r ) : A ( p ) , B ( q ) {
cout << " Derived class C constructor called with r = " << r <<
endl ;
}
};

int main () {
C obj (1 , 2 , 3) ;
return 0;
}

Base class A constructor called with x = 1


Base class B constructor called with y = 2
Derived class C constructor called with r = 3

5.10 Destructor in derived class


Destructors are called in the reverse order of constructors. That is, when a derived
object is destroyed, the destructor of the derived class is called first, followed by the
destructors of the base classes.

159
Chapter 5: Inheritance Object Oriented Programming

5.10.1 Destructor in Single Inheritance

Listing 106: Single Inheritance Destructor Call Order


# include < iostream >
using namespace std ;

class A {
public :
A () { cout << " Constructor of A \ n " ; }
~ A () { cout << " Destructor of A \ n " ; }
};

class B : public A {
public :
B () { cout << " Constructor of B \ n " ; }
~ B () { cout << " Destructor of B \ n " ; }
};

int main () {
B obj ;
return 0;
}

Constructor of A
Constructor of B
Destructor of B
Destructor of A

• The constructor of base class A is called before derived class B.

• On destruction, B’s destructor is called first, then A’s destructor.

5.10.2 Destructor in Multiple Inheritance

Listing 107: Multiple Inheritance Destructor Call Order


# include < iostream >
using namespace std ;

class A {
public :
A () { cout << " Constructor of A \ n " ; }
~ A () { cout << " Destructor of A \ n " ; }
};

class B {
public :
B () { cout << " Constructor of B \ n " ; }
~ B () { cout << " Destructor of B \ n " ; }
};

class C : public A , public B {


public :
C () { cout << " Constructor of C \ n " ; }
~ C () { cout << " Destructor of C \ n " ; }

160
Chapter 5: Inheritance Object Oriented Programming

};

int main () {
C obj ;
return 0;
}

Constructor of A
Constructor of B
Constructor of C
Destructor of C
Destructor of B
Destructor of A

• Constructors are called in the order: A → B → C.

• Destructors are called in reverse: C → B → A.

• This ensures proper cleanup starting from the most derived class.

• Constructor order: base → derived.

• Destructor order: derived → base.

• In multiple inheritance, base class constructors are called in the order they appear
in the inheritance list. Destructors are called in the reverse of that order.

5.11 Need of virtual base class

Person

Employee Student

Intern

Listing 108: C++ Program Demonstrating Multipath Inheritance


# include < iostream >
using namespace std ;

class Person {
protected :
string name ;
public :

161
Chapter 5: Inheritance Object Oriented Programming

void getName () {
cout << " Enter name : " ;
cin >> name ;
}
void showName () {
cout << " Name : " << name << endl ;
}
};

class Employee : virtual public Person {


protected :
int empID ;
public :
void getEmployee () {
cout << " Enter employee ID : " ;
cin >> empID ;
}
void showEmployee () {
cout << " Employee ID : " << empID << endl ;
}
};

class Student : virtual public Person {


protected :
int rollNo ;
public :
void getStudent () {
cout << " Enter roll number : " ;
cin >> rollNo ;
}
void showStudent () {
cout << " Roll Number : " << rollNo << endl ;
}
};

class Intern : public Employee , public Student {


public :
void getIntern () {
getName () ; // Only one copy of Person 's data
getEmployee () ;
getStudent () ;
}

void showIntern () {
showName () ;
showEmployee () ;
showStudent () ;
}
};

int main () {
Intern i ;
i . getIntern () ;
i . showIntern () ;
return 0;
}

In this program, we demonstrate multipath inheritance using virtual base classes

162
Chapter 5: Inheritance Object Oriented Programming

to avoid ambiguity.

• The base class Person contains a member function getName() that collects the
name of a person.

• Two classes, Employee and Student, inherit from Person using virtual public
inheritance. This makes Person a virtual base class.

• The Intern class inherits from both Employee and Student, forming a diamond-
shaped inheritance hierarchy.

If we inherit Person normally (without the virtual keyword), then both Employee
and Student will maintain their own separate copies of the Person class. This results in
two copies of the Person members in the Intern class, which leads to ambiguity:
Intern i ;
i . getName () ; // Error : ambiguous - two paths to getName ()

In this case, we would have to disambiguate explicitly:


i . Employee :: getName () ;
i . Student :: getName () ;

How Virtual Inheritance Solves the Problem


By using virtual public inheritance:
class Employee : virtual public Person { ... };
class Student : virtual public Person { ... };

The compiler ensures that there is only one shared copy of the Person class in the
entire inheritance chain. As a result, when the Intern class inherits from both Employee
and Student, it receives only one unique instance of the Person class, avoiding
ambiguity.
When calling i.getName() in the Intern object, the compiler uses the single shared
instance of Person:

• Intern → shared Person → getName()

This resolves the ambiguity and ensures that getName() is called safely without re-
quiring explicit path specification.
Multipath inheritance can lead to ambiguity when a base class is inherited more than
once through different paths. This is resolved using virtual inheritance, which ensures
only one shared copy of the base class exists in the derived class hierarchy.

163
Chapter 6: Virtual Functions Object Oriented Programming

Chapter 6: Virtual Functions


6.1 Need of virtual function
Virtual functions: Virtual means existing in appearance but not in reality. When
virtual functions are used, a program that appears to be calling a function of one class
may in reality be calling a function of a different class. Why are virtual functions needed?
Suppose you have a number of objects of different classes but you want to put them all
in an array and perform a particular operation on them using the same function call. For
example, suppose a graphics program includes several different shapes: a triangle, a ball,
a square, and so on. Each of these classes has a member function draw() that causes the
object to be drawn on the screen. Now suppose you plan to make a picture by grouping
a number of these elements together, and you want to draw the picture in a convenient
way. One approach is to create an array that holds pointers to all the different objects
in the picture. The array might be defined like this:

shape* ptrarr[100]; // array of 100 pointers to shapes

If you insert pointers to all the shapes into this array, you can then draw an entire picture
using a simple loop:

for(int j=0; j<N; j++)


ptrarr[j]->draw();

This is an amazing capability: Completely different functions are executed by the same
function call. If the pointer in ptrarr points to a ball, the function that draws a ball is
called; if it points to a triangle, the triangle-drawing function is called.
This is called polymorphism, which means different forms. The functions have
the same appearance, the draw() expression, but different actual functions are called,
depending on the contents of ptrarr[j]. Polymorphism is one of the key features of
object-oriented programming, after classes and inheritance.
For the polymorphic approach to work, several conditions must be met. First, all the
different classes of shapes, such as balls and triangles, must be descended from a single
base class (called shape). Second, the draw() function must be declared to be virtual
in the base class. This is all rather abstract, so let’s start with some short programs that
show parts of the situation, and put everything together later.
Listing 109: Normal Functions Accessed from Pointer
# include < iostream >
using namespace std ;

class Base // base class


{
public :
void show () // normal function
{ cout << " Base \ n " ; }
};

class Derv1 : public Base // derived class 1


{
public :

164
Chapter 6: Virtual Functions Object Oriented Programming

void show ()
{ cout << " Derv1 \ n " ; }
};

class Derv2 : public Base // derived class 2


{
public :
void show ()
{ cout << " Derv2 \ n " ; }
};

int main ()
{
Derv1 dv1 ; // object of derived class 1
Derv2 dv2 ; // object of derived class 2
Base * ptr ; // pointer to base class

ptr = & dv1 ; // put address of dv1 in pointer


ptr - > show () ; // execute show ()

ptr = & dv2 ; // put address of dv2 in pointer


ptr - > show () ; // execute show ()

return 0;
}

The Derv1 and Derv2 classes are derived from class Base. Each of these three classes has
a member function show(). In main() we create objects of class Derv1 and Derv2, and
a pointer to class Base. Then we put the address of a derived class object in the base
class pointer in the line:

ptr = &dv1; // derived class address in base class pointer

But wait—how can we get away with this? Doesn’t the compiler complain that we’re
assigning an address of one type (Derv1) to a pointer of another (Base)? On the contrary,
the compiler is perfectly happy, because type checking has been relaxed in this situation,
for reasons that will become apparent soon.
The rule is that pointers to objects of a derived class are type-compatible with pointers
to objects of the base class.
Now the question is, when you execute the line:

ptr->show();

what function is called? Is it Base::show() or Derv1::show()? Again, in the last two


lines of the program we put the address of an object of class Derv2 in the pointer, and
again execute:

ptr->show();

Which of the show() functions is called here? The output from the program answers
these questions:

Base
Base

165
Chapter 6: Virtual Functions Object Oriented Programming

As you can see, the function in the base class is always executed. The compiler ignores
the contents of the pointer ptr and chooses the member function that matches the type
of the pointer, as shown in Figure 62.
Sometimes this is what we want, but it doesn’t solve the problem posed at the beginning
of this section: accessing objects of different classes using the same statement.

Figure 62: Non virtual pointer access.

Let’s make a single change in our program: We’ll place the keyword virtual in front of
the declarator for the show() function in the base class.
Listing 110: Using virtual function for polymorphism
# include < iostream >
using namespace std ;
class Base // base class
{
public :
virtual void show () // virtual function
{ cout << " Base \ n " ; }
};
class Derv1 : public Base // derived class 1
{
public :
void show ()
{ cout << " Derv1 \ n " ; }
};
class Derv2 : public Base // derived class 2
{
public :
void show ()
{ cout << " Derv2 \ n " ; }

166
Chapter 6: Virtual Functions Object Oriented Programming

};

int main ()
{
Derv1 dv1 ; // object of derived class 1
Derv2 dv2 ; // object of derived class 2
Base * ptr ; // pointer to base class

ptr = & dv1 ; // put address of dv1 in pointer


ptr - > show () ; // calls Derv1 :: show ()

ptr = & dv2 ; // put address of dv2 in pointer


ptr - > show () ; // calls Derv2 :: show ()

return 0;
}

The output of this program is:


Derv1
Derv2
Now, as you can see, the member functions of the derived classes, not the base class, are
executed. We change the contents of ptr from the address of Derv1 to that of Derv2,
and the particular instance of show() that is executed also changes. So the same function
call
ptr->show();
executes different functions, depending on the contents of ptr. The rule is that the
compiler selects the function based on the contents of the pointer ptr, not on the type
of the pointer. This is shown in Figure 63.

Figure 63: Virtual Pointer Access

167
Chapter 6: Virtual Functions Object Oriented Programming

6.2 Late Binding[Run Time Polymorphism]


The astute reader may wonder how the compiler knows what function to compile. In
First Program, the compiler has no problem with the expression:

ptr->show();

It always compiles a call to the show() function in the base class. But in Second Program,
the compiler doesn’t know what class the contents of ptr may contain. It could be the
address of an object of the Derv1 class or of the Derv2 class. Which version of draw()
does the compiler call?
In fact, the compiler doesn’t know what to do, so it arranges for the decision to be deferred
until the program is running. At runtime, when it is known what class is pointed to by
ptr, the appropriate version of draw() will be called.
This is called late binding or dynamic binding. (Choosing functions in the normal
way, during compilation, is called early binding or static binding.) Late binding
requires some overhead but provides increased power and flexibility.

Figure 64: Runtime Polymorphism vs Compile Time Polymorphism

6.3 Array of Pointers to Base Class


In object-oriented programming, it is often useful to store pointers to objects of different
derived classes in a single array of pointers to the base class. This enables us to treat a
heterogeneous collection of objects uniformly, allowing polymorphic behavior when using
virtual functions.
Consider the following example where Base is a base class, and Derv1 and Derv2 are
derived classes. We create an array of pointers to Base, and store addresses of objects of
the derived classes in this array:
Listing 111: Array of pointers to base class example
# include < iostream >
using namespace std ;

class Base {
public :
virtual void show () {

168
Chapter 6: Virtual Functions Object Oriented Programming

cout << " Base \ n " ;


}
};

class Derv1 : public Base {


public :
void show () {
cout << " Derv1 \ n " ;
}
};

class Derv2 : public Base {


public :
void show () {
cout << " Derv2 \ n " ;
}
};

int main () {
Base * ptrarr [3]; // Array of pointers to Base

Derv1 obj1 ;
Derv2 obj2 ;
Base obj3 ;

ptrarr [0] = & obj1 ;


ptrarr [1] = & obj2 ;
ptrarr [2] = & obj3 ;

for ( int i = 0; i < 3; ++ i ) {


ptrarr [ i ] - > show () ; // Calls the appropriate show () function
}

return 0;
}

The output of this program will be:

Derv1
Derv2
Base

This demonstrates that although the array holds pointers to the base class, the appro-
priate overridden functions in the derived classes are called at runtime due to the use of
virtual functions. This mechanism is known as polymorphism.

6.4 Pure virtual functions and abstract class


Consider a situation, we will never create an object of the shape class itself; instead, we
create specific shapes such as circles and triangles. When we never want to instantiate
objects of a base class, we call it an abstract class. Such a class exists only to act
as a parent for derived classes that will be instantiated. It may also provide a common
interface for the class hierarchy. How can we make it clear to users of our class hierarchy
that the base class should not be instantiated? We could rely on documentation, but it
is much better to enforce this restriction in the code itself.

169
Chapter 6: Virtual Functions Object Oriented Programming

This is done by declaring at least one pure virtual function in the base class. A pure
virtual function is declared by assigning = 0 to its declaration. For example, in the shape
class, we can declare two pure virtual functions, getArea() and getPerimeter(), which
derived classes must override:
Listing 112: Abstract class shape with pure virtual functions
class shape {
public :
virtual double getArea () = 0; // pure virtual function
virtual double getPerimeter () = 0; // pure virtual function
};

Derived classes must provide implementations for these functions. Here is an example
with circle and rectangle classes:
Listing 113: Derived classes implementing pure virtual functions
# include < iostream >
# include < cmath >
using namespace std ;

class shape {
public :
virtual double getArea () = 0;
virtual double getPerimeter () = 0;
};

class circle : public shape {


double radius ;
public :
circle ( double r ) : radius ( r ) {}
double getArea () {
return M_PI * radius * radius ;
}
double getPerimeter () {
return 2 * M_PI * radius ;
}
};

class rectangle : public shape {


double width , height ;
public :
rectangle ( double w , double h ) : width ( w ) , height ( h ) {}
double getArea () {
return width * height ;
}
double getPerimeter () {
return 2 * ( width + height ) ;
}
};

int main () {
circle c (5.0) ;
rectangle r (4.0 , 6.0) ;

shape * shapes [2];


shapes [0] = & c ;
shapes [1] = & r ;

170
Chapter 6: Virtual Functions Object Oriented Programming

for ( int i = 0; i < 2; i ++) {


cout << " Area : " << shapes [ i ] - > getArea () << endl ;
cout << " Perimeter : " << shapes [ i ] - > getPerimeter () << endl ;
}
return 0;
}

Attempting to instantiate an object of shape directly will result in a compilation error,


ensuring the base class remains abstract.

6.5 Virtual Destructors


Base class destructors should always be virtual. Suppose you use delete with a
base class pointer to a derived class object to destroy the derived-class object. If the base-
class destructor is not declared virtual, then delete, like a normal member function,
calls only the destructor for the base class, not the destructor for the derived class.
This will cause only the base part of the object to be destroyed, potentially resulting in
resource leaks and undefined behavior.
# include < iostream >
# include < cmath >
using namespace std ;

class shape {
public :
virtual double getArea () = 0;
virtual double getPerimeter () = 0;
virtual ~ shape ()
{ cout < < " shape destructor " << endl ; }
};

class circle : public shape {


double radius ;
public :
circle ( double r ) : radius ( r ) {}
double getArea () {
return M_PI * radius * radius ;
}
double getPerimeter () {
return 2 * M_PI * radius ;
}
~ circle ()
{ cout < < " circle destructor " << endl ; }
};

class rectangle : public shape {


double width , height ;
public :
rectangle ( double w , double h ) : width ( w ) , height ( h ) {}
double getArea () {
return width * height ;
}
double getPerimeter () {
return 2 * ( width + height ) ;
}
~ rectangle ()

171
Chapter 6: Virtual Functions Object Oriented Programming

{ cout < < " rectangle destructor " << endl ; }


};

int main () {
shape * shapes [2];
shapes [0] = new circle (5.0) ;
shapes [1] = new rectangle (4.0 ,6.0) ;

for ( int i = 0; i < 2; i ++) {


cout << " Area : " << shapes [ i ] - > getArea () << endl ;
cout << " Perimeter : " << shapes [ i ] - > getPerimeter () << endl ;
}
for ( int i = 0; i < 2; i ++) {
delete shapes [ i ];
}
return 0;
}

6.6 The this Pointer


The member functions of every object have access to a sort of magic pointer named this,
which points to the object itself. Thus any member function can find out the address of
the object of which it is a member.
# include < iostream >
using namespace std ;

class where {
private :
char charray [10]; // occupies 10 bytes
public :
void reveal () {
cout << " \ nMy object 's address is " << this ;
}
};

int main () {
where w1 , w2 , w3 ; // make three objects
w1 . reveal () ; // see where they are
w2 . reveal () ;
w3 . reveal () ;
cout << endl ;
return 0;
}

The main() function creates three objects of the class where and calls the reveal()
function for each of them. The function prints the address of the current object by
using the this pointer, which is an implicit pointer to the calling object inside a member
function.
Below is an example output showing the memory addresses of the objects:

My object's address is 0x8f4effec


My object's address is 0x8f4effe2
My object's address is 0x8f4effd8

172
Chapter 6: Virtual Functions Object Oriented Programming

Since the data in each object consists of an array of 10 bytes, the objects are spaced 10
bytes apart in memory. (EC minus E2 is 10 decimal, as is E2 minus D8.) Some compilers
may place extra bytes in objects, making them slightly larger than 10 bytes.

6.6.1 Accessing Member Data with this


When you call a member function in C++, it comes into existence with the value of this
set to the address of the object for which the function was called. The this pointer can
be treated like any other pointer to an object, and can thus be used to access the data
in the object it points to.
This program simply prints out the value 11. Notice that the tester() member function
accesses the variable alpha as this->alpha. This is exactly the same as referring to
alpha directly. This syntax works, but there is no reason for it except to show that this
indeed points to the object.
# include < iostream >
using namespace std ;

class Simple {
private :
int alpha ;
public :
Simple ( int a ) {
this - > alpha = a ; // explicitly using ' this '
}

void tester () {
cout << " Value of alpha is : " << this - > alpha << endl ;
}
};

int main () {
Simple obj (11) ;
obj . tester () ;

return 0;
}

6.6.2 Using this for Returning Values


A more practical use for this is in returning values from member functions and overloaded
operators.
# include < iostream >
using namespace std ;

class alpha {
private :
int data ;
public :
alpha () { } // no - arg constructor
alpha ( int d ) { data = d ; } // one - arg constructor

void display () {
cout << data ;

173
Chapter 6: Virtual Functions Object Oriented Programming

alpha & operator =( const alpha & a ) { // overloaded = operator


data = a . data ; // not done automatically
cout << " \ nAssignment operator invoked " ;
return * this ; // return reference to this object
}
};

int main () {
alpha a1 (37) ;
alpha a2 , a3 ;

a3 = a2 = a1 ;
cout << " \ na2 = " ; a2 . display () ; // display a2
cout << " \ na3 = " ; a3 . display () ; // display a2
cout << endl ;

return 0;
}

Since this is a pointer to the object of which the function is a member, *this is that
object itself, and the statement returns it by reference.
Each time the equal sign is encountered in the expression

a3 = a2 = a1;

the overloaded operator=() function is called, which prints the messages. The three
objects all end up with the same value.

You usually want to return by reference from overloaded assignment operators, using
*this, to avoid the creation of extra objects.

6.6.3 Using this in Constructor


The this pointer is commonly used in constructors to resolve naming conflicts between
data members and constructor parameters with the same name.
# include < iostream >
using namespace std ;

class Student {
private :
string name ;
int roll ;

public :
Student ( string name , int roll ) {
this - > name = name ; // ' this ' resolves ambiguity
this - > roll = roll ;
}

void display () {
cout << " Name : " << name << " , Roll : " << roll << endl ;
}
};

174
Chapter 6: Virtual Functions Object Oriented Programming

int main () {
Student s1 ( " Alice " , 101) ;
s1 . display () ;
return 0;
}

In the above code, the this pointer refers to the current object and helps distinguish
between the constructor’s parameters and the class’s data members.

6.7 Reinterpret cast operator


The reinterpret cast is a type of casting operator in C++ used to convert one pointer
type to another, even if the types are completely unrelated. It performs a low-level
re-interpretation of the bit pattern of the value.

• Used for low-level casts that yield implementation-defined and potentially unsafe
results.

• Typically used to cast between unrelated pointer types or between integer and
pointer types.

• Should be used with extreme caution, as it can easily result in undefined behavior.

• Unlike static cast, it does not perform any safety checks at compile time.

Syntax:

reinterpret_cast<new_type>(expression)

Listing 114: Example of reinterpret cast


# include < iostream >
using namespace std ;

int main () {
int a = 65;
char * ptr = reinterpret_cast < char * >(& a ) ;
cout << " Integer a = " << a << endl ;
cout << " Reinterpreted as char = " << * ptr << endl ;
return 0;
}

Output:

Integer a = 65
Reinterpreted as char = A

Here, the integer a = 65 is reinterpreted as a character pointer. Since the ASCII


value of 65 is ’A’, dereferencing the pointer gives the character ’A’.

175
Chapter 6: Virtual Functions Object Oriented Programming

6.8 Run-time type information[RTTI]


It is possible to find out information about an object’s class and even change the class of
an object at runtime. C++ provides two mechanisms for this purpose:

• dynamic cast operator

• typeid operator

These are advanced capabilities, typically used when working with a variety of classes
that are descended (sometimes in complex ways) from a common base class.
The dynamic cast operator safely converts pointers and references to classes up and
down the inheritance hierarchy. It checks the validity of the cast at runtime, ensuring
type safety. If the cast is invalid, it returns a null pointer (in the case of pointers) or
throws a std::bad cast exception (for references).
Important: For dynamic cast to work, the base class must be polymorphic—it must
have at least one virtual function.
The typeid operator allows you to determine the exact type of an object at runtime.
It returns a reference to a type info object, which can be used to compare types or
extract type names. You must include the standard template library header typeinfo to
use the typeid operator.
Syntax of dynamic case:

pointer_to_derived = dynamic_cast<DerivedClass*>(pointer_to_base);

reference_to_derived = dynamic_cast<DerivedClass&>(reference_to_base);

The dynamic cast operator allows you to cast upward and downward in the inheritance
tree. However, it allows such casting only in limited ways.
Syntax of typeid:
typeid(expression)

Listing 115: Upcasting and Downcasting using dynamic cast


# include < iostream >
# include < typeinfo >
using namespace std ;

class Base {
protected :
int ba ;
public :
Base () : ba (0) { }
Base ( int b ) : ba ( b ) { }
virtual void vertFunc () { } // Required for RTTI

void show () {
cout << " Base : ba = " << ba << endl ;
}
};

class Derv : public Base {


private :

176
Chapter 6: Virtual Functions Object Oriented Programming

int da ;
public :
Derv ( int b , int d ) : Base ( b ) , da ( d ) {
}
void show () {
cout << " Derv : ba = " << ba << " , da = " << da << endl ;
}
};

int main () {
Base * pBase = new Base (10) ;
Derv * pDerv = new Derv (21 , 22) ;

// Upcasting : Derived to Base ( safe )


pBase = dynamic_cast < Base * >( pDerv ) ;
pBase - > show () ; // Output : Base : ba = 21

// pBase now points to a Derv object


pBase = new Derv (31 , 32) ;

// Downcasting : Base to Derived ( safe if pBase is pointing to Derv )


pDerv = dynamic_cast < Derv * >( pBase ) ;
if ( pDerv )
pDerv - > show () ; // Output : Derv : ba = 31 , da = 32
else
cout << " Dynamic cast failed . " << endl ;

return 0;
}

• A virtual function in Base enables Run-Time Type Information (RTTI).

• dynamic cast ensures type-safe conversion between base and derived pointers.

• Upcasting is always safe.

• Downcasting requires that the base pointer actually points to a derived object;
otherwise, the cast fails.

Listing 116: Using typeid with inheritance


# include < iostream >
# include < typeinfo > // Required for typeid
using namespace std ;

class Base {
public :
virtual void show () { cout << " Base class \ n " ; }
};

class Derived : public Base {


public :
void show () { cout << " Derived class \ n " ; }
};

int main () {
Base * b1 = new Base () ;

177
Chapter 6: Virtual Functions Object Oriented Programming

Base * b2 = new Derived () ;

cout << " Type of b1 : " << typeid (* b1 ) . name () << endl ;
cout << " Type of b2 : " << typeid (* b2 ) . name () << endl ;

delete b1 ;
delete b2 ;
return 0;
}

Sample Output
Type of b1: 4Base
Type of b2: 7Derived

• Base has a virtual function show(), making it polymorphic.

• typeid(*b1) returns the type of the object b1 points to, which is Base.

• typeid(*b2) returns the type of the object b2 points to, which is Derived, even
though the pointer type is Base*.

• Without a virtual function in the base class, both typeid(*b1) and typeid(*b2)
would return Base, due to static binding.

Note: The actual output of typeid(...).name() depends on the compiler (e.g.,


GCC, MSVC). It may show as class Base, Base, or a mangled name.

178
Chapter 7: Stream Computation Object Oriented Programming

Chapter 7: Stream Computation


7.1 Input/Output stream class hierarchy
A stream is a general name given to a flow of data. In C++, a stream is represented by
an object of a particular class. So far, we have used the cin and cout stream objects.
These are predefined objects in the iostream library:

• cin is an object of class istream, used for input from standard input (usually the
keyboard).

• cout is an object of class ostream, used for output to standard output (usually the
screen).

C programmers may wonder what advantages there are to using the stream classes for
I/O instead of traditional C functions such as printf() and scanf(), and—for files—
fprintf(), fscanf(), and so on.

One major advantage is simplicity. If you’ve ever mistakenly used a %d formatting


character instead of %f in printf(), you’ll appreciate the difference. There are no such
formatting characters in streams, since each object already knows how to display itself.
This removes a major source of errors.

Another advantage is that you can overload existing operators and functions,
such as the insertion (<<) and extraction (>>) operators, to work with classes that you
create. This allows your own classes to behave in the same way as built-in types, mak-
ing programming easier, more consistent, and less error-prone—not to mention more
aesthetically satisfying.

You may wonder whether stream I/O is important if you plan to program in an
environment with a graphical user interface (GUI), such as Windows, where direct text
output to the screen is not commonly used. Should you still learn about C++ streams?
Yes, because they are the best way to:

• Write data to files.

• Format data in memory.

• Interface with text input/output windows and other GUI elements.

The stream classes are arranged in a rather complex hierarchy.

179
Chapter 7: Stream Computation Object Oriented Programming

Figure 65: Stream class hierarchy

We’ve already made extensive use of some stream classes. The extraction operator >>
is a member of the std::istream class, and the insertion operator << is a member of the
std::ostream class. Both of these classes are derived from the std::ios class, which in
turn is derived from std::ios base. The std::cout object, representing the standard
output stream, which is usually directed to the video display, is a predefined object of
the std::ostream class. Similarly, std::cin is a predefined object of the std::istream
class.
The classes used for input and output to the video display and keyboard are declared
in the header file <iostream>, which we have routinely included in previous examples.
The classes used specifically for disk file I/O are declared in the header file <fstream>.
Figure 65 illustrates which classes belong to these header files.
Additionally, some manipulators (such as std::setw(), std::setprecision(), etc.)
are declared in the <iomanip> header, which is used for controlling the format of input
and output.
If you are curious about the internal structure of these stream classes, it can be educa-
tional to explore the source or documentation of these headers provided by your compiler
in its include directory. Many questions about stream behavior and functionality can
be answered by examining the class definitions, inheritance relationships, and constant
declarations.
The istream and ostream classes are derived from the ios class and are dedicated
to input and output operations, respectively.

• The istream class handles input operations. It provides member functions such as:

– get() – for reading individual characters


– getline() – for reading entire lines

180
Chapter 7: Stream Computation Object Oriented Programming

– read() – for reading a block of binary data


– Overloaded extraction operator >> – for formatted input

• The ostream class handles output operations. It provides functions such as:

– put() – for writing individual characters


– write() – for writing a block of binary data
– Overloaded insertion operator << – for formatted output

These classes form the foundation of stream-based I/O in C++, enabling both low-
level and high-level data handling in a consistent and extensible manner. The iostream
class is derived from both istream and ostream using multiple inheritance. This
allows it to support both input and output operations simultaneously.
Classes derived from iostream can be used with devices that support bidirectional
data flow, such as disk files that are opened for both reading and writing.
For example, the fstream class is derived from iostream and enables reading from
and writing to the same file within a single program, using the same stream object.

7.2 Stream Errors


So far in this book, we’ve mostly used a straightforward approach to input and output,
using statements of the form:

cout << "Good morning";


cin >> var;

However, as you may have discovered, this approach assumes that nothing will go
wrong during the I/O process. Unfortunately, this isn’t always the case, especially with
input.
What happens if a user enters the string "nine" instead of the integer 9? Or presses
the Enter key without entering anything? Or what if there’s a hardware failure?
In this section, we will explore how to handle such problems using the error-handling
capabilities of C++ streams. Many of the techniques discussed here are also applicable
to file input and output operations.

7.2.1 Error-Status Bits


The stream error-status flags are part of the std::ios class and are defined as an enum
member. These flags are used to report errors that may occur during input or output
operations.
Various member functions of the ios class can be used to check, clear, or even set
these error flags manually. These functions are essential for writing robust I/O code that
can detect and handle unexpected conditions during stream operations.

181
Chapter 7: Stream Computation Object Oriented Programming

Figure 66: Error-status Flags

Figure 67: Function of Error Flags

7.2.2 Inputting Numbers


Let’s see how to handle errors when inputting numbers. This approach is applicable to
numbers read either from the keyboard or from a disk file. The idea is to check the state
of the stream using the goodbit flag (or related functions), and if the stream is not in a
good state, signal an error and allow the user to try again. This method helps prevent
program crashes and ensures that the user inputs valid data before the program proceeds.
// Program to input a valid integer using while loop
# include < iostream >
using namespace std ;

int main () {
int number ;

while ( true ) {
cout << " Enter an integer : " ;
cin >> number ;

if ( cin . good () ) {
break ; // Valid input , exit loop
}

// Input failed : clear error state and show error


cin . clear () ;
cin . ignore (10 , '\ n ') ;
cout << " Invalid input . Try again .\ n " ;
}

cout << " You entered : " << number << endl ;

182
Chapter 7: Stream Computation Object Oriented Programming

return 0;
}

The most common error this scheme detects when reading keyboard input is the user
typing nondigits (for instance, “nine” instead of “9”). This causes the failbit to be set.
However, it also detects system-related failures that are more common with disk files.

7.3 Unformatted Input and Output


Unformatted input and output in C++ refers to operations that read or write data
without any special formatting or conversion. These operations deal with raw characters
or bytes directly, unlike formatted I/O which interprets data types and applies formatting
rules.
Unformatted I/O functions are useful for reading or writing binary data, characters,
or when precise control over input/output is required.

• istream::get() — Reads a single character from input without skipping whites-


pace.

• istream::getline() — Reads characters into a buffer until a delimiter or maxi-


mum length is reached.

• istream::read() — Reads a specified number of bytes from a stream (used for


binary input).

• ostream::put() — Writes a single character to output.

• ostream::write() — Writes a specified number of bytes to a stream (used for


binary output).

Syntax:

• To read a character:
cin.get(var);

• To read a line:
cin.getline(array, size);

• To write a character:
cout.put(char);

• To write a block of data:


cout.write(buffer, size);

# include < iostream >


using namespace std ;

int main () {
char ch ;

cout << " Enter a character : " ;


cin . get ( ch ) ; // unformatted input

183
Chapter 7: Stream Computation Object Oriented Programming

cout << " You entered : " ;


cout . put ( ch ) ; // unformatted output
cout << endl ;

return 0;
}

# include < iostream >


using namespace std ;

int main () {
char str [50];

cout << " Enter your name : " ;


cin . getline ( str , 50) ; // reads a line including spaces

cout << " Hello , " ;


cout . write ( str , 50) ; // writes up to 50 characters
cout << endl ;

return 0;
}

7.4 Formatted Input and Output


Formatting flags are a set of enum definitions in the ios class. They act as on/off switches
that specify choices for various aspects of input and output format and operation.

Figure 68: Formatting Flags

There are several ways to set the formatting flags, and different ones can be set in
different ways. Since they are members of the ios class, you must usually precede them
with the name ios and the scope-resolution operator (for example, ios::skipws).

184
Chapter 7: Stream Computation Object Oriented Programming

All the flags can be set using the setf() and unsetf() ios member functions. Look
at the following example:

cout.setf(ios::left); // left justify output text


cout << "This text is left-justified";
cout.unsetf(ios::left); // return to default (right justified)

Many formatting flags can be set using manipulators, so let’s look at them now.
Manipulators are formatting instructions inserted directly into a stream. We’ve seen
examples before, such as the manipulator endl, which sends a newline to the stream and
flushes it:

cout << "To each his own." << endl;

cout << setiosflags(ios::fixed) // use fixed decimal point


<< setiosflags(ios::showpoint) // always show decimal point
<< var;

As these examples demonstrate, manipulators come in two flavors: those that take
an argument and those that don’t. Table 12.2 summarizes the important no-argument
manipulators.

Figure 69: No argument ios manipulators

You insert these manipulators directly into the stream. For example, to output var
in hexadecimal format, you can write:

cout << hex << var;

Note that manipulators affect only the data that follows them in the stream, not the
data that precedes them. Table 12.3 summarizes the important manipulators that take
arguments. You need the <iomanip> header file for these functions.

185
Chapter 7: Stream Computation Object Oriented Programming

Figure 70: Ios Manipulators with arguments

The ios class contains a number of functions that you can use to set the formatting
flags and perform other tasks. Table 12.4 shows most of these functions, except those
that deal with errors, which we’ll examine separately.

Figure 71: IOS Functions

These functions are called for specific stream objects using the normal dot operator.
For example, to set the field width to 14, you can write:

cout.width(14);

The following statement sets the fill character to an asterisk (as for check printing):

cout.fill('*');

You can use several functions to manipulate the ios formatting flags directly. For
example, to set left justification, use:

cout.setf(ios::left);

To restore right justification, use:

cout.unsetf(ios::left);

186
Chapter 7: Stream Computation Object Oriented Programming

A two-argument version of setf() uses the second argument to reset all the flags
of a particular type or field. Then the flag specified in the first argument is set. This
makes it easier to reset the relevant flags before setting a new one. Table 12.5 shows the
arrangement.
For example:

cout.setf(ios::left, ios::adjustfield);

clears all the flags dealing with text justification and then sets the left flag for left-
justified output.

Figure 72: Two Argument version of setf()

By using the techniques shown here with the formatting flags, you can usually figure
out a way to format I/O not only for the keyboard and display, but, as we’ll see later in
this chapter, for files as well.
The following program reads a decimal number from the user and displays its equiva-
lent hexadecimal and octal representations. It uses the setf() member function of cout
with the ios::basefield mask to safely set the numeric base format for output.
# include < iostream >
using namespace std ;

int main () {
int decimalNumber ;

cout << " Enter a decimal number : " ;


cin >> decimalNumber ;

// Display decimal ( default )


cout << " Decimal : " << decimalNumber << endl ;

// Set flags to hexadecimal


cout . setf ( ios :: hex , ios :: basefield ) ;
cout << " Hexadecimal : " << decimalNumber << endl ;

// Set flags to octal


cout . setf ( ios :: oct , ios :: basefield ) ;
cout << " Octal : " << decimalNumber << endl ;

// Reset to decimal for any future output


cout . setf ( ios :: dec , ios :: basefield ) ;

return 0;
}

187
Chapter 7: Stream Computation Object Oriented Programming

Enter a decimal number: 42


Decimal: 42
Hexadecimal: 2a
Octal: 52

The left and right formatting flags are used to align the text within a specified
width. Here, the same text is printed twice — first left-justified and then right-justified
— both within a width of 50 characters.
// Program to demonstrate left and right justification

# include < iostream >


# include < iomanip > // for std :: setw and std :: setf
using namespace std ;

int main () {
string text = " Justify this text " ;

// Left justification
cout . setf ( ios :: left , ios :: adjustfield ) ;
cout << setw (50) << text << endl ;

// Right justification
cout . setf ( ios :: right , ios :: adjustfield ) ;
cout << setw (50) << text << endl ;

return 0;
}

Output

Justify this text


Justify this text

A different approach can also give same output:


// Program to left and right justify text using width () and setf ()

# include < iostream >


using namespace std ;

int main () {
cout . width (50) ;
cout . setf ( ios :: left ) ;
cout << " This text is left justified . " << endl ;

cout . unsetf ( ios :: left ) ; // Clear left justification


cout . width (50) ;
cout << " This text is right justified . " ;

return 0;
}

Output

Justify this text


Justify this text

188
Chapter 7: Stream Computation Object Oriented Programming

The precision() function in C++ is used to control the number of significant digits
displayed for floating-point numbers. This function is particularly useful when we want
to limit or standardize the output format of decimal numbers. The following program
demonstrates how to use precision() to display a floating-point number with varying
levels of precision.
Listing 117: Display Floating-Point Number Using precision()
# include < iostream >
using namespace std ;

int main () {
double num = 123.456789;

cout << " Default precision : " << num << endl ;

cout . precision (4) ;


cout << " Precision set to 4: " << num << endl ;

cout . precision (2) ;


cout << " Precision set to 2: " << num << endl ;

return 0;
}

Default precision: 123.457


Precision set to 4: 123.5
Precision set to 2: 1.2e+02
The following program shows how to use ios formatting flags scientific and fixed
to display a floating-point number in scientific notation and fixed-point notation respec-
tively. The setf() function is used to set these flags on the output stream.
Listing 118: Display Floating Number in Scientific and Fixed Formats
# include < iostream >
using namespace std ;

int main () {
double num = 12345.6789;

// Default format
cout << " Default format : " << num << endl ;

// Scientific format
cout . setf ( ios :: scientific , ios :: floatfield ) ;
cout << " Scientific format : " << num << endl ;

// Fixed format
cout . setf ( ios :: fixed , ios :: floatfield ) ;
cout << " Fixed format : " << num << endl ;

// Reset to default ( optional )


cout . unsetf ( ios :: floatfield ) ;
cout << " Back to default format : " << num << endl ;

return 0;
}

189
Chapter 7: Stream Computation Object Oriented Programming

Default format: 12345.7


Scientific format: 1.234568e+04
Fixed format: 12345.678900
Back to default format: 12345.7

The setw() manipulator in C++ sets the width of the next output field. It is com-
monly used to align output in columns or format text neatly. The following example
demonstrates how setw() affects the display of numbers and strings.
Listing 119: Illustration of setw() Usage
# include < iostream >
# include < iomanip > // Required for setw
using namespace std ;

int main () {
cout << " Without setw : " << endl ;
cout << 123 << " " << 4567 << endl ;

cout << " \ nWith setw (10) : " << endl ;


cout << setw (10) << 123 << " " << setw (10) << 4567 << endl ;

cout << " \ nWith setw (10) and left justification : " << endl ;
cout << left ;
cout << setw (10) << 123 << " " << setw (10) << 4567 << endl ;

return 0;
}

Without setw:
123 4567

With setw(10):
123 4567

With setw(10) and left justification:


123 4567

The setfill() manipulator in C++ is used to specify the character that fills the
unused spaces when setting a field width using setw(). This helps in formatting output
by replacing the default space character with a custom fill character. The following
program demonstrates this concept.
Listing 120: Illustration of setfill() Usage
# include < iostream >
# include < iomanip > // Required for setw and setfill
using namespace std ;

int main () {
cout << " Default fill character ( space ) : " << endl ;
cout << setw (10) << 123 << endl ;

cout << " \ nUsing setfill ( '* ') : " << endl ;
cout << setfill ( '* ') << setw (10) << 123 << endl ;

190
Chapter 7: Stream Computation Object Oriented Programming

cout << " \ nUsing setfill ( '# ') with left justification : " << endl ;
cout << setfill ( '# ') << left << setw (10) << 123 << endl ;

return 0;
}

Default fill character (space):


123

Using setfill('*'):
*******123

Using setfill('#') with left justification:


123#######

The setprecision() manipulator in C++ is used to specify the number of significant


digits displayed when outputting floating-point numbers. This helps control the precision
of the displayed values. The following program demonstrates this feature with different
precision settings.
Listing 121: Illustration of setprecision() Usage
# include < iostream >
# include < iomanip > // Required for setprecision
using namespace std ;

int main () {
double pi = 3 . 1 4 1 5 9 2 6 5 3 5 8 9 7 9 3 2 3 8 4 6 ;

cout << " Default precision : " << pi << endl ;

cout << setprecision (5) ;


cout << " Precision set to 5: " << pi << endl ;

cout << setprecision (10) ;


cout << " Precision set to 10: " << pi << endl ;

return 0;
}

Default precision: 3.14159


Precision set to 5: 3.1416
Precision set to 10: 3.141592654

191
Chapter 8: Templates Object Oriented Programming

Chapter 8: Templates

192
Chapter 9: Exception Handling Object Oriented Programming

Chapter 9: Exception Handling

193
REFERENCES Object Oriented Programming

References
[1] R. Lafore, Object-Oriented Programming in C++, 4th ed. Indianapolis, IN, USA:
Sams Publishing, 2002.

194

You might also like