Download as pdf or txt
Download as pdf or txt
You are on page 1of 59

OBJECT ORIENTED PROGRAMMING

UNIT 1

Procedural programming
• It is a paradigm that structures a program as a sequence of procedures or routines, each
representing a specific task or operation to be performed.
• In procedural programming languages, the focus is on creating procedures that are
executed in a step-by-step manner. These procedures may have inputs (parameters)
and produce outputs (return values), and they often manipulate shared data.

Key characteristics of procedural programming languages include:


1. Procedures or Functions: Programs are organized into procedures or functions, which
are self-contained blocks of code designed to perform a specific task. Each procedure
typically has a well-defined purpose and receives input, processes it, and produces
output.
2. Sequential Execution: The program is executed sequentially, line by line, from the
beginning to the end. Control structures like loops and conditionals are used to alter the
flow of execution.
3. Shared Data: Data is often shared among procedures. Global variables can be accessed
and modified by any part of the program. This can lead to potential issues such as
unintended side effects or difficulties in tracking changes to the data.
4. Emphasis on Algorithms: Procedural languages often focus on algorithms and the
steps involved in solving a problem. Programs are structured around the logical flow of
operations.
5. Limited Code Reusability: Code reuse is typically achieved through the creation of
procedures that can be called from various parts of the program. However, the level of
modularity and reusability may be more limited compared to other programming
paradigms.
6. Example Procedural Languages: Examples of procedural programming
languages include C, Pascal, and Fortran.

#include <stdio.h>
// Function to calculate the sum of two // Calling the 'add' function
numbers int result = add(num1, num2);
int add(int a, int b) {
return a + b; // Printing the result
} printf("The sum is: %d\n", result);
int main() {
int num1 = 5; return 0;
int num2 = 7; }

In this example, the program consists of procedures (`add` and `main`). The `add` function
performs a specific task (adding two numbers), and the `main` function is the starting point of
the program. The focus is on defining procedures and organizing the program's logic through
sequential execution.
Advantages of Procedural Programming:
1. Simplicity and Readability: Procedural code is often straightforward and easy to read,
making it accessible for beginners and facilitating quick understanding of the program's
logic.

2. Efficient Execution: Procedural languages tend to be efficient in terms of execution


speed since they follow a simple and direct sequence of steps.

3. Control Over System Resources: Procedural programming provides a high level of


control over system resources, making it suitable for systems programming and
applications where low-level access is crucial.

4. Well-Suited for Small to Medium-Sized Projects: Procedural programming can be


well-suited for smaller projects with straightforward requirements, where the simplicity
of the paradigm is an advantage.

5. Ease of Compilation: Compilation of procedural code is often straightforward, and the


resulting machine code can be efficient, leading to good performance.

6. Clear Flow of Execution: The sequential nature of procedural code results in a clear
flow of execution, making it easier for developers to understand the logic and make
modifications.

7. Suitable for Teaching Programming Basics: Procedural programming is often used


in introductory programming courses to teach fundamental concepts and build a solid
understanding of programming principles.

Limitations of Procedural Programming:


1. Lack of Modularity: Procedural programming can lead to less modular and more
monolithic code, making it challenging to manage and maintain as the program grows
in size and complexity.

2. Difficulty in Code Reusability: Reusing code can be more challenging compared to


other paradigms. Functions are often specific to a particular task, and achieving high
levels of code reusability may require extra effort.

3. Data Security and Integrity: Shared data can be accessed and modified by any part
of the program, potentially leading to unintended side effects and difficulties in
maintaining data security and integrity.

4. Limited Real-World Modeling: Procedural programming may not align well with
real-world entities and their relationships. Modeling complex systems based solely on
procedures might result in less intuitive and reflective code.

5. Limited Support for Parallel Execution: Procedural programming languages may


have limitations when it comes to efficiently exploiting parallelism in modern computer
architectures. This can impact performance in multi-core systems.
6. Less Suitable for Large Projects: As programs grow in size and complexity,
procedural code may become harder to manage, leading to increased chances of errors
and difficulties in debugging.

Object-Oriented Programming (OOP)

• Object-oriented programming (OOP) is a computer programming model that


organizes software design around data, or objects, rather than functions and logic.
• OOP focuses on the objects that developers want to manipulate rather than the logic
required to manipulate them. This approach to programming is well-suited for
programs that are large, complex and actively updated or maintained.
• The organization of an object-oriented program also makes the method beneficial
to collaborative development, where projects are divided into groups. Additional
benefits of OOP include code reusability, scalability and efficiency.
• In fact, it is one of the most popular methods in many programming languages, such
as Java, Python, C++, etc.

What is the structure of object-oriented programming?


The structure of object-oriented programming includes the following:
1. Classes: It is a user-defined data types that act as the blueprint for individual objects,
attributes and methods. It represents the set of properties or methods that are common
to all objects of one type. A class is like a blueprint for an object.
2. Objects: An Object is an instance of a Class. When a class is defined, no memory is
allocated but when it is instantiated (i.e. an object is created) memory is allocated. An
object has an identity, state, and behavior. Each object contains data and code to
manipulate the data. Objects can interact without having to know details of each
other’s data or code, it is sufficient to know the type of message accepted and type of
response returned by the objects.
3. Methods: They are functions that are defined inside a class that describe the behaviors
of an object. In classes, methods are responsible to modify or define the behavior of the
class and it’s objects. It’s a logic or procedure defined in a class to do something.
Methods in classes layout the behavior for objects that will be created. For instance, if a
car owner presses the horn button it’ll perform an operation by horning. Similar to
attributes the essence of defining methods in a class is to enable consistency, readability,
simplicity, maintainability and ease of reuse with modification by objects where
necessary. The syntax of a method is similar to a function but is defined and maintained
by the class. Similar behaviour (action or methods) of cars can be defined in the car class
instead of having to define separate functions for every car that’s been created..
4. Attributes: Attributes are data members inside a class or an object that represent the
different features of the class. They can also be referred to as characteristics of the class
that can be accessed from other objects or differentiate a class from other classes. For
example, a car attribute includes: tire, door, seats, license plate, headlight, wheel, handle,
make, and year. Defining variables in a class is to keep the code simple and maintainable.
In the case of a car, the attributes mentioned above are similar hence the need of defining
them while creating the car class.

• Instance Attribute An instance attribute is the data member of an object. Its scope
of access is within the object creation and is defined inside the constructor
(automatically executed method when an object is created from a class) of a class.
• Class Attribute The attributes defined in a class that can be shared or accessed by
its objects and is defined outside the constructor.

Procedural Programming vs Object-Oriented Programming


Procedural Oriented Programming Object-Oriented Programming

In object-oriented programming, the


In procedural programming, the program is
program is divided into small parts
divided into small parts called functions.
called objects.

Procedural programming follows a top- Object-oriented programming follows


down approach. a bottom-up approach.

Object-oriented programming has access


There is no access specifier in procedural
specifiers like private, public, protected,
programming.
etc.

Adding new data and functions is not easy. Adding new data and function is easy.
Procedural Oriented Programming Object-Oriented Programming

Procedural programming does not have any Object-oriented programming provides


proper way of hiding data so it is less secure. data hiding so it is more secure.

In procedural programming, overloading is Overloading is possible in object-oriented


not possible. programming.

In object-oriented programming, the


In procedural programming, there is no
concept of data hiding and inheritance is
concept of data hiding and inheritance.
used.

In procedural programming, the function is In object-oriented programming, data is


more important than the data. more important than function.

Procedural programming is based on Object-oriented programming is based on


the unreal world. the real world.

Procedural programming is used for Object-oriented programming is used for


designing medium-sized programs. designing large and complex programs.

Procedural programming uses the concept of Object-oriented programming uses the


procedure abstraction. concept of data abstraction.

Code reusability absent in procedural Code reusability present in object-oriented


programming, programming.

Examples: C, FORTRAN, Pascal, Basic,


Examples: C++, Java, Python, C#, etc.
etc.

Why do we need object-oriented programming


• To make the development and maintenance of projects more effortless.
• To provide the feature of data hiding that is good for security concerns.
• We can solve real-world problems if we are using object-oriented programming.
• It ensures code reusability.
• It lets us write generic code: which will work with a range of data, so we don’t
have to write basic stuff over and over again.

What are the benefits of OOP?


• Modularity. Encapsulation enables objects to be self-contained, making
troubleshooting and collaborative development easier.
• Reusability. Code can be reused through inheritance, meaning a team does not have to
write the same code multiple times.
• Productivity. Programmers can construct new programs quicker through the use of
multiple libraries and reusable code.
• Easily upgradable and scalable. Programmers can implement system functionalities
independently.
• Interface descriptions. Descriptions of external systems are simple, due to message
passing techniques that are used for objects communication.
• Security. Using encapsulation and abstraction, complex code is hidden, software
maintenance is easier and internet protocols are protected.
• Flexibility. Polymorphism enables a single function to adapt to the class it is placed in.
Different objects can also pass through the same interface.

Characteristics of Object-Oriented Programming


OOP has several key characteristics that distinguish it from other programming paradigms.
1. Classes and Objects:
- Classes: Classes are blueprints or templates that define the structure and behavior
of objects. They encapsulate data and methods that operate on the data.
- Objects: Objects are instances of classes. They represent real-world entities and
have specific attributes (data) and behaviors (methods).

2. Encapsulation: Encapsulation is the bundling of data and methods that operate on that
data within a single unit, i.e., a class. It helps in hiding the internal details of how an
object's data is implemented, promoting information hiding and reducing complexity.

3. Inheritance: Inheritance is a mechanism that allows a new class (subclass or derived


class) to inherit attributes and behaviors from an existing class (superclass or base
class). It promotes code reuse and establishes a hierarchical relationship between
classes.

4. Polymorphism: Polymorphism allows objects of different classes to be treated as


objects of a common superclass. This facilitates flexibility and extensibility, enabling
code to work with objects of multiple types without knowing their specific classes.

5. Abstraction: Abstraction involves simplifying complex systems by modeling classes


based on essential properties and behaviors. It allows developers to focus on what an
object does rather than how it achieves its functionality.

6. Data Hiding: Data hiding restricts the access to certain details of an object and exposes
only what is necessary. This helps in preventing unintended interference with an object's
internal state, enhancing security and stability.

7. Messaging: Objects communicate with each other through method calls. This
messaging system allows objects to interact and collaborate, enabling the building of
complex systems with well-defined interfaces.

8. Dynamic Binding: Dynamic binding allows the selection of a specific method or


implementation at runtime, rather than compile-time. This contributes to the flexibility
of OOP systems.
9. Association: Association represents relationships between objects. It can be a one-to-
one, one-to-many, or many-to-many relationship, reflecting how objects collaborate
and interact with each other.

10. Consistency and Standardization: OOP promotes a consistent and standardized way
of designing and organizing code. It follows principles like the SOLID principles to
ensure maintainability, scalability, and readability.

These characteristics collectively contribute to the strengths of Object-Oriented Programming,


such as modularity, code reusability, maintainability, and the ability to model real-world entities
and relationships effectively.

Difference between abstraction and data hiding: While they are related, they serve
distinct purposes.
Abstraction Data Hiding
Definition Abstraction is the process of Data hiding is a concept that emphasizes
simplifying complex systems by restricting access to the internal details of
modeling classes based on the an object, encapsulating its state and
essential properties and implementation details.
behaviors they share, while
ignoring or hiding the irrelevant
details
Purpose It focuses on what an object does It helps in controlling access to the internal
rather than how it achieves its data of an object to prevent unintended
functionality manipulation and to maintain a clear
separation between the object's interface
and its implementation.

Example Consider a `Vehicle` class. The In the `Vehicle` class, the details of the
essential properties and engine, such as the type of fuel injection
behaviors of a vehicle might system or the number of cylinders, can be
include methods like `start()`, considered private and hidden from
`stop()`, and properties like external access. This information is
`speed` and `fuelLevel`. The encapsulated within the class, and external
implementation details of how code should interact with the `Vehicle`
the engine starts or how the through its public interface (e.g., methods
brakes work are abstracted away. like `start()` and `stop()`). This way, the
Users of the `Vehicle` class don't internal details of the engine are hidden,
need to know these low-level and the implementation can be changed
details; they can interact with the without affecting the code that uses the
high-level methods and `Vehicle` class.
properties.

Abstraction focuses on simplifying complex systems by modeling classes based on essential


properties and behaviors, while data hiding is concerned with encapsulating the internal details
of an object to control access and maintain a clear separation between the interface and
implementation.
Abstraction is more about the high-level design of classes, while data hiding is about the
implementation details and protecting the internal state of an object.
Datatypes in C++: Data types are used to tell the variables the type of data they can store.
Whenever a variable is defined in C++, the compiler allocates some memory for that variable
based on the data type with which it is declared. They specify the size and types of values to
be stored.

Data Types in C++ are divided into 3 Types:

1. Primitive Data Types: These data types are built-in or predefined data types and can be
used directly by the user to declare variables. example: int, char, float, bool, etc. Primitive
data types available in C++ are:
• Integer • Double Floating Point
• Character • Valueless or Void
• Boolean • Wide Character
• Floating Point

2. Derived Data Types: Derived data types that are derived from the primitive or built-in
datatypes are referred to as Derived Data Types. These can be of four types namely:
• Function • Pointer
• Array • Reference

3. Abstract or User-Defined Data Types: Abstract or User-Defined data types are defined
by the user itself. Like, defining a class in C++ or a structure. C++ provides the following
user-defined datatypes:
• Class • Enumeration
• Structure • Typedef defined Datatype
• Union

Primitive Data Types


• Integer: The keyword used for integer data types is int. Integers typically
require 4 bytes of memory space.

• Character: Character data type is used for storing characters. The keyword used
for the character data type is char. Characters typically require 1 byte of memory
space and range from -128 to 127 or 0 to 255.

• Boolean: Boolean data type is used for storing Boolean or logical values. A
Boolean variable can store either true or false. The keyword used for the Boolean
data type is bool.
• Floating Point: Floating Point data type is used for storing single-precision
floating-point values or decimal values. The keyword used for the floating-point
data type is float. Float variables typically require 4 bytes of memory space.

• Double Floating Point: Double Floating Point data type is used for storing
double-precision floating-point values or decimal values. The keyword used for
the double floating-point data type is double. Double variables typically require
8 bytes of memory space.
• void: Void means without any value. void data type represents a valueless
entity. A void data type is used for those function which does not return a value.

• Wide Character: Wide character data type is also a character data type but this
data type has a size greater than the normal 8-bit data type. Represented
by wchar_t. It is generally 2 or 4 bytes long.

• sizeof() operator: sizeof() operator is used to find the number of bytes occupied
by a variable/data type in computer memory.

// C++ Program to Demonstrate the correct size of various data types on your computer.
#include <iostream>
using namespace std;
int main()
{
cout << "Size of char : " << sizeof(char) << endl;
cout << "Size of int : " << sizeof(int) << endl;
cout << "Size of long : " << sizeof(long) << endl;
cout << "Size of float : " << sizeof(float) << endl;
cout << "Size of double : " << sizeof(double) << endl;
return 0;
}

Output
Size of char : 1
Size of int : 4
Size of long : 8
Size of float : 4
Size of double : 8

C++ Variables: A variable is a container (storage area) to hold data. To indicate the storage
area, each variable should be given a unique name (identifier). For example,

int age = 14;

Here, age is a variable of the int data type, and we have assigned an integer value 14 to it.
The value of a variable can be changed, hence the name variable.

int age = 14; // age is 14


age = 17; // age is 17

Rules for naming a variable


1. A variable name can only have alphabets, numbers, and the underscore _.
2. A variable name cannot begin with a number.
3. It is a preferred practice to begin variable names with a lowercase character. For
example, name is preferable to Name.
4. A variable name cannot be a keyword. For example, int is a keyword that is used to
denote integers.
5. A variable name can start with an underscore. However, it's not considered a good
practice.

C++ Literals: Literals are data used for representing fixed values. They can be used
directly in the code. For example: 1, 2.5, 'c' etc.
Here, 1, 2.5 and 'c' are literals. Why? You cannot assign different values to these terms.
Here's a list of different literals in C++ programming.
1. Integers: An integer is a numeric literal(associated with numbers) without any fractional
or exponential part. There are three types of integer literals in C programming:
decimal (base 10)
octal (base 8)
hexadecimal (base 16)

For example:
Decimal: 0, -9, 22 etc
Octal: 021, 077, 033 etc
Hexadecimal: 0x7f, 0x2a, 0x521 etc
In C++ programming, octal starts with a 0, and hexadecimal starts with a 0x.
2. Floating-point Literals: A floating-point literal is a numeric literal that has either a
fractional form or an exponent form. For example:

-2.0
0.0000234

3. Characters: A character literal is created by enclosing a single character inside single


quotation marks. For example: 'a', 'm', 'F', '2', '}' etc.

4. Escape Sequences: Sometimes, it is necessary to use characters that cannot be typed or


has special meaning in C++ programming. For example, newline (enter), tab, question mark,
etc.
In order to use these characters, escape sequences are used.

Escape Sequences Characters

\b Backspace

\f Form feed

\n Newline

\r Return

\t Horizontal tab
\v Vertical tab

\\ Backslash

\' Single quotation mark

\" Double quotation mark

\? Question mark

\0 Null Character

5. String Literals: A string literal is a sequence of characters enclosed in double-quote


marks. For example:

"good" string constant

"" null string constant

"" string constant of six white space

"x" string constant having a single character

"Earth is round\n" prints string with a newline

C++ Constants: We can create variables whose value cannot be changed. For that, we use
the const keyword. Here's an example:
const int LIGHT_SPEED = 299792458;
LIGHT_SPEED = 2500 // Error! LIGHT_SPEED is a constant.
Here, we have used the keyword const to declare a constant named LIGHT_SPEED. If we try
to change the value of LIGHT_SPEED, we will get an error.

C++ Basic Input/Output


C++ Output: In C++, cout sends formatted output to standard output devices, such as the
screen. We use the cout object along with the << operator for displaying output.

Example 1: String Output


#include <iostream>
using namespace std;

int main() {
// prints the string enclosed in double quotes
cout << "This is C++ Programming";
return 0;
}
Output
This is C++ Programming
How does this program work?
- We first include the iostream header file that allows us to display output.
- The cout object is defined inside the std namespace. To use the std namespace, we used
the using namespace std; statement.
- Every C++ program starts with the main() function. The code execution begins from the
start of the main() function.
- cout is an object that prints the string inside quotation marks " ". It is followed by
the << operator.
- return 0; is the "exit status" of the main() function. The program ends with this
statement, however, this statement is not mandatory.

Note: If we don't include the using namespace std; statement, we need to use std::cout instead
of cout. This is the preferred method as using the std namespace can create potential
problems.
However, we have used the std namespace in our tutorials in order to make the codes more
readable.

#include <iostream>
int main() {
// prints the string enclosed in double quotes
std::cout << "This is C++ Programming";
return 0;
}

Example 2: Numbers and Characters Output


To print the numbers and character variables, we use the same cout object but without using
quotation marks.
#include <iostream>
using namespace std;
int main() {
int num1 = 70;
double num2 = 256.783;
char ch = 'A';
cout << num1 << endl; // print integer
cout << num2 << endl; // print double
cout << "character: " << ch << endl; // print char
return 0;
}
Output
70
256.783
character: A

Notes: The endl manipulator is used to insert a new line. That's why each output is displayed
in a new line.
The << operator can be used more than once if we want to print different variables, strings
and so on in a single statement. For example:
cout << "character: " << ch << endl;
C++ Input: In C++, cin takes formatted input from standard input devices such as the
keyboard. We use the cin object along with the >> operator for taking input.

Example 3: Integer Input/Output


#include <iostream>
using namespace std;
int main() {
int num;
cout << "Enter an integer: ";
cin >> num; // Taking input
cout << "The number is: " << num;
return 0;
}
Output
Enter an integer: 70
The number is: 70

In the program, we used


cin >> num;
to take input from the user. The input is stored in the variable num. We use the >> operator
with cin to take input.

C++ Taking Multiple Inputs cout << "Character: " << a << endl;
#include <iostream> cout << "Number: " << num;
using namespace std; return 0;
int main() { }
char a; Output
int num; Enter a character and an integer: F
cout << "Enter a character and an 23
integer: "; Character: F
cin >> a >> num; Number: 23

ARRAYS
• Arrays are a fundamental data structure in C++, providing a simple and efficient way
to organize and access collections of data
• In C++, an array is a collection of elements of the same data type, stored in contiguous
memory locations.
• Arrays provide a convenient way to group related data under a single name and allow
for easy access and manipulation of individual elements using an index.

Here's a basic overview of arrays in C++:

1. Declaration and Initialization: Arrays are declared by specifying the data type of their
elements, followed by the array name and the size of the array in square brackets.

// Declaration of an integer array with size 5


int numbers[5];

Initialization can be done at the time of declaration or later using a loop or explicit assignment.

// Initialization at the time of declaration


int values[3] = {1, 2, 3};
// Initialization later
for (int i = 0; i < 5; ++i) {
numbers[i] = i * 2;
}

2. Accessing Elements: Elements in an array are accessed using an index, starting from 0 for
the first element.
int thirdValue = values[2]; // Accessing the third element

Array indices must be within the valid range (0 to size-1) to avoid accessing memory outside
the array, which could lead to undefined behavior.

4. Multidimensional Arrays: Arrays can have more than one dimension, creating matrices or
higher-dimensional structures.

// 2D array (matrix)
int matrix[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};

5. Size of Arrays: The size of a statically declared array is fixed at compile time and cannot be
changed during program execution.

OPERATORS in C++: Operators are symbols that perform operations on variables and
values. For example, + is an operator used for addition, while - is an operator used for
subtraction.
Operators in C++ can be classified into 6 types:
1. Arithmetic Operators
2. Assignment Operators
3. Relational Operators
4. Logical Operators
5. Bitwise Operators
6. Other Operators
1. C++ Arithmetic Operators: Arithmetic operators are used to perform arithmetic
operations on variables and data. For example,
a + b;
Here, the + operator is used to add two variables a and b. Similarly there are various other
arithmetic operators in C++.

Operator Operation

+ Addition

- Subtraction

* Multiplication

/ Division
% Modulo Operation (Remainder after division)

Example 1: Arithmetic Operators


#include <iostream>
using namespace std;
int main() {
int a, b;
a = 7;
b = 2;
cout << "a + b = " << (a + b) << endl; // printing the sum of a and b
cout << "a - b = " << (a - b) << endl; // printing the difference of a and b
cout << "a * b = " << (a * b) << endl; // printing the product of a and b
cout << "a / b = " << (a / b) << endl; // printing the division of a by b
cout << "a % b = " << (a % b) << endl; // printing the modulo of a by b
return 0;
}
Output
a+b=9
a-b=5
a * b = 14
a/b=3
a%b=1

Here, the operators +, - and * compute addition, subtraction, and multiplication respectively
as we might have expected.

/ Division Operator
Note the operation (a / b) in our program. The / operator is the division operator.
As we can see from the above example, if an integer is divided by another integer, we will get
the quotient. However, if either divisor or dividend is a floating-point number, we will get the
result in decimals.
In C++,
7/2 is 3
7.0 / 2 is 3.5
7 / 2.0 is 3.5
7.0 / 2.0 is 3.5

% Modulo Operator
The modulo operator % computes the remainder. When a = 9 is divided by b = 4, the
remainder is 1.
Note: The % operator can only be used with integers.

Increment and Decrement Operators


C++ also provides increment and decrement operators: ++ and -- respectively.
++ increases the value of the operand by 1
-- decreases it by 1
For example,
int num = 5;
// increment operator
++num; // 6

Here, the code ++num; increases the value of num by 1.

Example 2: Increment and Decrement Operators


// Working of increment and decrement operators
#include <iostream>
using namespace std;
int main() {
int a = 10, b = 100, result_a, result_b;

// incrementing a by 1 and storing the result in result_a


result_a = ++a;
cout << "result_a = " << result_a << endl;

// decrementing b by 1 and storing the result in result_b


result_b = --b;
cout << "result_b = " << result_b << endl;
return 0;
}
Output
result_a = 11
result_b = 99
In the above program, we have used the ++ and -- operators as prefixes (++a and --b).
However, we can also use these operators as postfix (a++ and b--).

2. C++ Assignment Operators: In C++, assignment operators are used to assign values to
variables. For example,
a = 5; // assign 5 to a
Here, we have assigned a value of 5 to the variable a.

Operator Example Equivalent to

= a = b; a = b;

+= a += b; a = a + b;

-= a -= b; a = a - b;

*= a *= b; a = a * b;

/= a /= b; a = a / b;

%= a %= b; a = a % b;
Example 3: Assignment Operators
#include <iostream>
using namespace std;
int main() {
int a, b;
a = 2; // 2 is assigned to a
b = 7; // 7 is assigned to b
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "\nAfter a += b;" << endl;

a += b; // a = a +b // assigning the sum of a and b to a


cout << "a = " << a << endl;
return 0;
}
Output
a=2
b=7

After a += b;
a=9

3. C++ Relational Operators: A relational operator is used to check the relationship


between two operands. For example,
a > b; // checks if a is greater than b
Here, > is a relational operator. It checks if a is greater than b or not.
If the relation is true, it returns 1 whereas if the relation is false, it returns 0.

Operator Meaning Example

== Is Equal To 3 == 5 gives us false

!= Not Equal To 3 != 5 gives us true

> Greater Than 3 > 5 gives us false

< Less Than 3 < 5 gives us true

Greater Than or Equal


>= 3 >= 5 give us false
To

<= Less Than or Equal To 3 <= 5 gives us true

Example 4: Relational Operators


#include <iostream>
using namespace std;
int main() {
int a, b;
a = 3;
b = 5;
bool result;

result = (a == b); // false


cout << "3 == 5 is " << result << endl;

result = (a != b); // true


cout << "3 != 5 is " << result << endl;

result = a > b; // false


cout << "3 > 5 is " << result << endl;

result = a < b; // true


cout << "3 < 5 is " << result << endl;

result = a >= b; // false


cout << "3 >= 5 is " << result << endl;

result = a <= b; // true


cout << "3 <= 5 is " << result << endl;

return 0;
}
Output
3 == 5 is 0
3 != 5 is 1
3 > 5 is 0
3 < 5 is 1
3 >= 5 is 0
3 <= 5 is 1

Note: Relational operators are used in decision-making and loops.

4. C++ Logical Operators: Logical operators are used to check whether an expression
is true or false. If the expression is true, it returns 1 whereas if the expression is false, it
returns 0.

Operator Example Meaning

Logical AND.
expression1 &&
&& True only if all the operands are
expression2
true.

Logical OR.
|| expression1 || expression2 True if at least one of the operands
is true.
Logical NOT.
! !expression
True only if the operand is false.

In C++, logical operators are commonly used in decision making. To further understand the
logical operators, let's see the following examples,
Suppose,
a=5
b=8

Then,
(a > 3) && (b > 5) evaluates to true
(a > 3) && (b < 5) evaluates to false
(a > 3) || (b > 5) evaluates to true
(a > 3) || (b < 5) evaluates to true
(a < 3) || (b < 5) evaluates to false
!(a < 3) evaluates to true
!(a > 3) evaluates to false

Example 5: Logical Operators


#include <iostream>
using namespace std;

int main() {
bool result;

result = (3 != 5) && (3 < 5); // true


cout << "(3 != 5) && (3 < 5) is " << result << endl;

result = (3 == 5) && (3 < 5); // false


cout << "(3 == 5) && (3 < 5) is " << result << endl;

result = (3 == 5) && (3 > 5); // false


cout << "(3 == 5) && (3 > 5) is " << result << endl;

result = (3 != 5) || (3 < 5); // true


cout << "(3 != 5) || (3 < 5) is " << result << endl;

result = (3 != 5) || (3 > 5); // true


cout << "(3 != 5) || (3 > 5) is " << result << endl;

result = (3 == 5) || (3 > 5); // false


cout << "(3 == 5) || (3 > 5) is " << result << endl;

result = !(5 == 2); // true


cout << "!(5 == 2) is " << result << endl;

result = !(5 == 5); // false


cout << "!(5 == 5) is " << result << endl;

return 0;
}
Output
(3 != 5) && (3 < 5) is 1
(3 == 5) && (3 < 5) is 0
(3 == 5) && (3 > 5) is 0
(3 != 5) || (3 < 5) is 1
(3 != 5) || (3 > 5) is 1
(3 == 5) || (3 > 5) is 0
!(5 == 2) is 1
!(5 == 5) is 0

Explanation of logical operator program


- (3 != 5) && (3 < 5) evaluates to 1 because both operands (3 != 5) and (3 <
5) are 1 (true).
- (3 == 5) && (3 < 5) evaluates to 0 because the operand (3 == 5) is 0 (false).
- (3 == 5) && (3 > 5) evaluates to 0 because both operands (3 == 5) and (3 >
5) are 0 (false).
- (3 != 5) || (3 < 5) evaluates to 1 because both operands (3 != 5) and (3 < 5) are 1 (true).
- (3 != 5) || (3 > 5) evaluates to 1 because the operand (3 != 5) is 1 (true).
- (3 == 5) || (3 > 5) evaluates to 0 because both operands (3 == 5) and (3 >
5) are 0 (false).
- !(5 == 2) evaluates to 1 because the operand (5 == 2) is 0 (false).
- !(5 == 5) evaluates to 0 because the operand (5 == 5) is 1 (true).

5. C++ Bitwise Operators: In C++, bitwise operators are used to perform operations on
individual bits. They can only be used alongside char and int data types.

Operator Description

& Binary AND

| Binary OR

^ Binary XOR

~ Binary One's Complement

<< Binary Shift Left

>> Binary Shift Right

6. Other C++ Operators: Here is a list of some other common operators available in C++.

Operator Description Example


sizeof returns the size of data type sizeof(int); // 4

returns value based on the string result = (5 > 0) ?


?:
condition "even" : "odd"; // "even"

represents memory address of the


& &num; // address of num
operand

accesses members of struct


. s1.marks = 92;
variables or class objects

used with pointers to access the


-> ptr->marks = 92;
class or struct variables

<< prints the output value cout << 5;

>> gets the input value cin >> num;

Reference: In C++, a reference is an alias or alternative name for an existing variable. It


provides a way to access the value of a variable using a different identifier. Unlike pointers,
references cannot be reassigned to refer to a different variable once they are initialized.

Here is a basic overview of references in C++:

1. Declaration and Initialization: To declare a reference, you use the ampersand (&) symbol
followed by the type, and it is initialized with an existing variable.
int original = 42;
int& alias = original; // 'alias' is a reference to 'original'

2. Use of References: Once a reference is initialized, you can use it just like the original
variable. Changes made through the reference affect the original variable.
alias = 99; // 'original' now also becomes 99

3. Function Parameters: References are commonly used as function parameters to avoid


unnecessary copying of large objects.
void modifyValue(int& ref) {
ref += 10;
}

int number = 5;
modifyValue(number); // 'number' becomes 15

4. Avoiding Copying: References are often used to avoid the overhead of copying objects,
especially in function calls or when passing parameters.
5. References vs. Pointers: Unlike pointers, references cannot be `NULL` or reassigned to
refer to a different variable. References are often considered safer than pointers because they
are less prone to errors like null pointer dereference.

6. Initialization Requirements: References must be initialized when declared, and they must
always refer to a valid object throughout their lifetime.

int& invalidReference; // Error: references must be initialized

7. Returning References from Functions: It's possible to return a reference from a function,
allowing the function result to be used as an lvalue.
int& getReference() {
static int value = 42;
return value;
}

int& result = getReference(); // 'result' is a reference to the static variable

References are a powerful feature in C++ that facilitate more readable and efficient code by
providing an alternative name for variables, especially in cases where modifying the original
variable is desired. They are widely used in functions, classes, and other contexts where
aliasing can be beneficial.

// C++ Program to demonstrate use of references


#include <iostream>
using namespace std;
int main ()
{
int x = 10;
int& ref = x; // ref is a reference to x.
ref = 20; // Value of x is now changed to 20
cout << "x = " << x << '\n';
x = 30; // Value of x is now changed to 30
cout << "ref = " << ref << '\n';
return 0;
}
Output:
x = 20
ref = 30

Difference between reference and pointer:


Here are some reasons why references are perceived as more powerful than pointers in specific
scenarios:

1. Simplicity and Readability: References provide a more concise and readable syntax. The
usage of `&` in the declaration makes it clear that a reference is being used, and the syntax for
accessing the value is more straightforward compared to pointers.
int number = 42;
// Using a reference
int& ref = number;
ref = 99; // Changes 'number' directly

// Using a pointer
int* ptr = &number;
*ptr = 99; // Also changes 'number', but syntax is less direct

2. No Need for Null Checks: References cannot be `NULL` and must be initialized upon
declaration. This eliminates the need for null checks that are often necessary when using
pointers.

int* ptr = nullptr; // Pointer must be checked for null before use
int& ref = ???; // References must be initialized, eliminating null issues

3. Initialization Requirement: References must be initialized when declared, which enforces


that they always refer to a valid object. This helps prevent common pointer-related issues like
dereferencing null pointers.
int* ptr = nullptr; // Valid, but may lead to runtime errors if dereferenced
int& ref = ???; // Error, must be initialized when declared

4. No Reassignment: Once a reference is initialized, it cannot be reassigned to refer to a


different variable. This prevents accidental changes to the referenced variable.
int original = 42;
int& ref = original;
int* ptr = &original;

ref = 99; // Changes 'original'


ptr = ???; // Allows reassignment to a different variable, potentially introducing bugs

5. Automatic Dereferencing: References automatically dereference when used, making the


syntax cleaner and more intuitive.
int number = 42;
int& ref = number;

int* ptr = &number;


int value = *ptr; // Dereferencing is explicit with pointers
int another = ref; // Dereferencing is implicit with references

C++ Flow Control: C++ is a programming language from a high level that is widely used
for creating applications and software. One of the most important concepts in C++
programming is Flow Control, which refers to the ability to direct the flow of a program based
on specific conditions. This allows developers to control how their programs execute and can
help to make them more efficient and effective.
Conditional Statements: Conditional Statements are used in C++ to run a certain piece of
program only if a specific condition is met. There are generally three types of conditional
statements in C++: if, if-else, and switch.

if Statement: The if statement is the simplest of the three and is used to run a certain piece of
code Only if a certain condition is true. For example:

int x = 5;
if (x == 5) {
std::cout << "x is 5" << std::endl;
}
In this example, the block of code inside the curly braces will only be executed if the condition
inside the parentheses is true.

if-else Statement: The if-else statement is used when we want to execute some code only if
some condition exists. If the given condition is true then code will be executed otherwise else
statement will be used to run other part of the code.For example:
int x = 5;
if (x == 5) {
std::cout << "x is 5" << std::endl;
} else {
std::cout << "x is not 5" << std::endl;
}
In this example, if the condition inside the parentheses is true, the first block of code will be
executed. Otherwise, the second block of code will be executed.

switch Statement: The switch statement is used to execute different blocks of code based on
the value of a variable. For example:
switch (variable) {
case value1:
// code to execute if the variable is equal to value1
break;
case value2:
// code to execute if the variable is equal to value2
break;
// add more cases as needed
default:
// code to execute if the variable does not match any case
}
C++ code:
int x = 2;
switch (x) {
case 1:
std::cout << "x is 1" << std::endl;
break;
case 2:
std::cout << "x is 2" << std::endl;
break;
default:
std::cout << "x is not 1 or 2" << std::endl;
break;
}
In this example, the switch statement will execute the block of code associated with the value
of x. If x is 1, the first block of code will be executed. If x is 2, the second block of code will
be executed. If x is any other value, the default block of code will be executed.

Loops: Loops are used in C++ to execute a block of code multiple times, either until a certain
condition is met or for a specific number of times. There are generally three types of loops in
C++: while, do-while, and for.

While Loop: The while loop is used to execute when we want to run some code for until
some specific condition matches. For example:
int x = 0;
while (x < 5) {
std::cout << x << std::endl;
x++;
}
In this example, the while loop will continue to execute the block of code inside the curly
braces as long as x is less than 5. Each time the loop executes, the value of x will be incremented
by 1.

do-while Loop: The do-while loop is the same as the while loop, but the condition is
checked after the first iteration of the loop. For example:
int x = 0;
do {
std::cout << x << std::endl;
x++;
} while (x < 5);
In this example, the do-while loop will execute the block of code inside the curly brackets, and
then it will check the condition. So it will be executed a minimum of one time.

for Loop: The for loop allows a program to execute a piece of program a fixed number of
times. The syntax for the for loop is:
for (initialization; condition; increment/decrement) {
// code to execute repeatedly
}
Here is an example that uses the for loop to print the numbers from 1 to 10:
for (int i = 1; i <= 10; i++) {
cout << i << " ";
}

C++ Continue Statement: The C++ continue statement is used to continue loop. It
continues the current flow of the program and skips the remaining code at specified condition.
In case of inner loop, it continues only inner loop.
continue;

C++ Continue Statement Example


#include <iostream>
using namespace std;
int main()
{
for(int i=1;i<=10;i++){
if(i==5){
continue;
}
cout<<i<<"\n";
}
}
Output:
1
2
3
4
6
7
8
9
10

C++ Continue Statement with Inner Loop: C++ Continue Statement continues inner loop
only if you use continue statement inside the inner loop.
#include <iostream>
using namespace std;
int main()
{
for(int i=1;i<=3;i++){
for(int j=1;j<=3;j++){
if(i==2&&j==2){
continue;
}
cout<<i<<" "<<j<<"\n";
}
}
}
Output:
11
12
13
21
23
31
32
33

C++ Goto Statement: The C++ goto statement is also known as jump statement. It is used
to transfer control to the other part of the program. It unconditionally jumps to the specified
label.
It can be used to transfer control from deeply nested loop or switch case label.

C++ Goto Statement Example


#include <iostream>
using namespace std;
int main()
{
ineligible:
cout<<"You are not eligible to vote!\n";
cout<<"Enter your age:\n";
int age;
cin>>age;
if (age < 18){
goto ineligible;
}
else
{
cout<<"You are eligible to vote!";
}
}
Output:
You are not eligible to vote!
Enter your age:
16
You are not eligible to vote!
Enter your age:
7
You are not eligible to vote!
Enter your age:
22
You are eligible to vote!

C++ Classes/Objects

Everything in C++ is associated with classes and objects, along with its attributes and methods. For
example: in real life, a car is an object. The car has attributes, such as weight and color,
and methods, such as drive and brake.

Attributes and methods are basically variables and functions that belongs to the class. These are often
referred to as "class members".

A class is a user-defined data type that we can use in our program, and it works as an object
constructor, or a "blueprint" for creating objects.
Create a Class: To create a class, use the class keyword:
Create a class called "MyClass":
class MyClass { // The class
public: // Access specifier
int myNum; // Attribute (int variable)
string myString; // Attribute (string variable)
};

Example explained
• The class keyword is used to create a class called MyClass.
• The public keyword is an access specifier, which specifies that members (attributes and
methods) of the class are accessible from outside the class. You will learn more about access
specifiers later.
• Inside the class, there is an integer variable myNum and a string variable myString. When
variables are declared within a class, they are called attributes.
• At last, end the class definition with a semicolon ;.

Create an Object:
In C++, an object is created from a class. We have already created the class named MyClass, so now
we can use this to create objects.

To create an object of MyClass, specify the class name, followed by the object name.

To access the class attributes (myNum and myString), use the dot syntax (.) on the object:
Example

Create an object called "myObj" and access the attributes:

class MyClass { // The class


public: // Access specifier
int myNum; // Attribute (int variable)
string myString; // Attribute (string variable)
};

int main() {
MyClass myObj; // Create an object of MyClass

// Access attributes and set values


myObj.myNum = 15;
myObj.myString = "Some text";

// Print attribute values


cout << myObj.myNum << "\n";
cout << myObj.myString;
return 0;
}

Multiple Objects: You can create multiple objects of one class


// Create a Car class with some attributes
class Car {
public:
string brand;
string model;
int year;
};

int main() {
// Create an object of Car
Car carObj1;
carObj1.brand = "BMW";
carObj1.model = "X5";
carObj1.year = 1999;

// Create another object of Car


Car carObj2;
carObj2.brand = "Ford";
carObj2.model = "Mustang";
carObj2.year = 1969;

// Print attribute values


cout << carObj1.brand << " " << carObj1.model << " " << carObj1.year << "\n";
cout << carObj2.brand << " " << carObj2.model << " " << carObj2.year << "\n";
return 0;
}

Access Specifiers: Access specifiers define how the members (attributes and methods) of a class
can be accessed. In the example above, the members are public - which means that they can be
accessed and modified from outside the code.
In C++, there are three access specifiers:

• public - members are accessible from outside the class


• private - members cannot be accessed (or viewed) from outside the class
• protected - members cannot be accessed from outside the class, however, they can be accessed
in inherited classes.

In the following example, we demonstrate the differences between public and private members:
Example
class MyClass {
public: // Public access specifier
int x; // Public attribute
private: // Private access specifier
int y; // Private attribute
};

int main() {
MyClass myObj;
myObj.x = 25; // Allowed (public)
myObj.y = 50; // Not allowed (private)
return 0;
}

If you try to access a private member, an error occurs:

error: y is private

Note: It is possible to access private members of a class using a public method inside the same class.

Tip: It is considered good practice to declare your class attributes as private (as often as you can). This
will reduce the possibility of yourself (or others) to mess up the code.

Note: By default, all members of a class are private if you don't specify an access specifier:

Example
class MyClass {
int x; // Private attribute
int y; // Private attribute
};
Class Methods: Methods are functions that belongs to the class.
There are two ways to define functions that belongs to a class:

• Inside class definition


• Outside class definition

In the following example, we define a function inside the class, and we name it "myMethod".

Note: You access methods just like you access attributes; by creating an object of the class and using
the dot syntax (.):

Inside Example
class MyClass { // The class
public: // Access specifier
void myMethod() { // Method/function defined inside the class
cout << "Hello World!";
}
};

int main() {
MyClass myObj; // Create an object of MyClass
myObj.myMethod(); // Call the method
return 0;
}

To define a function outside the class definition, you have to declare it inside the class and then define
it outside of the class. This is done by specifiying the name of the class, followed the scope
resolution :: operator, followed by the name of the function:
Outside Example
class MyClass { // The class
public: // Access specifier
void myMethod(); // Method/function declaration
};

// Method/function definition outside the class


void MyClass::myMethod() {
cout << "Hello World!";
}

int main() {
MyClass myObj; // Create an object of MyClass
myObj.myMethod(); // Call the method
return 0;
}
Inline Functions: C++ provides inline functions to reduce the function call overhead. An inline
function is a function that is expanded in line when it is called. When the inline function is called whole
code of the inline function gets inserted or substituted at the point of the inline function call. This
substitution is performed by the C++ compiler at compile time. An inline function may increase
efficiency if it is small.

Syntax:
inline return-type function-name(parameters)
{
// function code
}
Remember, inlining is only a request to the compiler, not a command. The compiler can ignore the
request for inlining.
The compiler may not perform inlining in such circumstances as:
- If a function contains a loop. (for, while and do-while)
- If a function contains static variables.
- If a function is recursive.
- If a function return type is other than void, and the return statement doesn’t exist in a function
body.
- If a function contains a switch or goto statement.
Why Inline Functions are Used?
When the program executes the function call instruction the CPU stores the memory address of the
instruction following the function call, copies the arguments of the function on the stack, and finally
transfers control to the specified function. The CPU then executes the function code, stores the function
return value in a predefined memory location/register, and returns control to the calling function. This
can become overhead if the execution time of the function is less than the switching time from the caller
function to called function (callee).
For functions that are large and/or perform complex tasks, the overhead of the function call is usually
insignificant compared to the amount of time the function takes to run. However, for small, commonly-
used functions, the time needed to make the function call is often a lot more than the time needed to
actually execute the function’s code. This overhead occurs for small functions because the execution
time of a small function is less than the switching time.
Inline functions Advantages:
1. Function call overhead doesn’t occur.
2. It also saves the overhead of push/pop variables on the stack when a function is called.
3. It also saves the overhead of a return call from a function.
4. When you inline a function, you may enable the compiler to perform context-specific
optimization on the body of the function. Such optimizations are not possible for normal function
calls. Other optimizations can be obtained by considering the flows of the calling context and the
called context.
5. An inline function may be useful (if it is small) for embedded systems because inline can yield
less code than the function called preamble and return.
Inline function Disadvantages:
1. The added variables from the inlined function consume additional registers, After the in-lining
function if the variable number which is going to use the register increases then they may create
overhead on register variable resource utilization. This means that when the inline function body
is substituted at the point of the function call, the total number of variables used by the function
also gets inserted. So the number of registers going to be used for the variables will also get
increased. So if after function inlining variable numbers increase drastically then it would surely
cause overhead on register utilization.
2. If you use too many inline functions then the size of the binary executable file will be large,
because of the duplication of the same code.
3. Too much inlining can also reduce your instruction cache hit rate, thus reducing the speed of
instruction fetch from that of cache memory to that of primary memory.
4. The inline function may increase compile time overhead if someone changes the code inside the
inline function then all the calling location has to be recompiled because the compiler would be
required to replace all the code once again to reflect the changes, otherwise it will continue with
old functionality.
5. Inline functions may not be useful for many embedded systems. Because in embedded systems
code size is more important than speed.
6. Inline functions might cause thrashing because inlining might increase the size of the binary
executable file. Thrashing in memory causes the performance of the computer to degrade. The
following program demonstrates the use of the inline function.
Inline Function Example:

#include <iostream>
using namespace std;
inline int cube(int s) { return s * s * s; }
int main()
{
cout << "The cube of 3 is: " << cube(3) << "\n";
return 0;
}

Output
The cube of 3 is: 27

Inline function and classes


It is also possible to define the inline function inside the class. In fact, all the functions defined inside
the class are implicitly inline. Thus, all the restrictions of inline functions are also applied here. If you
need to explicitly declare an inline function in the class then just declare the function inside the class
and define it outside the class using the inline keyword.

Syntax:
class S
{
public:
inline int square(int s) // redundant use of inline
{
// this function is automatically inline
// function body
}
};
The above style is considered a bad programming style. The best programming style is to just write the
prototype of the function inside the class and specify it as an inline in the function definition.

For Example:
class S
{
public:
int square(int s); // declare the function
};

inline int S::square(int s) // use inline prefix


{
}

// C++ Program to demonstrate inline functions and classes


#include <iostream>

using namespace std;

class operation {
int a, b, add, sub, mul;
float div;

public:
void get();
void sum();
void difference();
void product();
void division();
};
inline void operation ::get()
{
cout << "Enter first value:";
cin >> a;
cout << "Enter second value:";
cin >> b;
}

inline void operation ::sum()


{
add = a + b;
cout << "Addition of two numbers: " << a + b << "\n";
}

inline void operation ::difference()


{
sub = a - b;
cout << "Difference of two numbers: " << a - b << "\n";
}

inline void operation ::product()


{
mul = a * b;
cout << "Product of two numbers: " << a * b << "\n";
}

inline void operation ::division()


{
div = a / b;
cout << "Division of two numbers: " << a / b << "\n";
}

int main()
{
cout << "Program using inline function\n";
operation s;
s.get();
s.sum();
s.difference();
s.product();
s.division();
return 0;
}

Output:
Enter first value: 45
Enter second value: 15
Addition of two numbers: 60
Difference of two numbers: 30
Product of two numbers: 675
Division of two numbers: 3
What is wrong with the macro?
The C language uses macro. The preprocessor replaces all macro calls directly within the macro code. It
is recommended to always use the inline function instead of the macro. According to Dr. Bjarne
Stroustrup, the creator of C++ macros are almost never necessary in C++ and they are error-prone. There
are some problems with the use of macros in C++. Macro cannot access private members of the class.
Macros look like function calls but they are actually not.

// C++ Program to demonstrate working of macro


#include <iostream>
using namespace std;
class S {
int m;

public:
// error
#define MAC(S::m)
};

Output:
Error: "::" may not appear in macro parameter list
#define MAC(S::m)
C++ compiler checks the argument types of inline functions and necessary conversions are performed
correctly. The preprocessor macro is not capable of doing this. One other thing is that the macros are
managed by the preprocessor and inline functions are managed by the C++ compiler. Remember: It is
true that all the functions defined inside the class are implicitly inline and the C++ compiler will perform
inline calls of these functions, but the C++ compiler cannot perform inline if the function is virtual. The
reason is called to a virtual function is resolved at runtime instead of compile-time. Virtual means waiting
until runtime and inline means during compilation, if the compiler doesn’t know which function will be
called, how it can perform inlining? One other thing to remember is that it is only useful to make the
function inline if the time spent during a function call is more compared to the function body execution
time.
An example where the inline function has no effect at all:
inline void show()
{
cout << "value of S = " << S << endl;
}
The above function relatively takes a long time to execute. In general, a function that performs an input-
output (I/O) operation shouldn’t be defined as inline because it spends a considerable amount of time.
Technically inlining of the show() function is of limited value because the amount of time the I/O
statement will take far exceeds the overhead of a function call. Depending upon the compiler you are
using the compiler may show you a warning if the function is not expanded inline.
Programming languages like Java & C# don’t support inline functions. But in Java, the compiler can
perform inlining when the small final method is called because final methods can’t be overridden by
subclasses, and the call to a final method is resolved at compile time.
The last thing to keep in mind is that inline functions are a valuable feature of C++. Appropriate use of
inline functions can provide performance enhancement but if inline functions are used arbitrarily then
they can’t provide better results. In other words, don’t expect a better performance of the program. Don’t
make every function inline. It is better to keep inline functions as small as possible.

C++ friend Function and friend Classes


Data hiding is a fundamental concept of object-oriented programming. It restricts the access of private
members from outside of the class.
Similarly, protected members can only be accessed by derived classes and are inaccessible from
outside. For example,
class MyClass {
private:
int member1;
}
int main() {
MyClass obj;

// Error! Cannot access private members from here.


obj.member1 = 5;
}
However, there is a feature in C++ called friend functions that break this rule and allow us to access
member functions from outside the class.

friend Function in C++: A friend function can access the private and protected data of a class.
We declare a friend function using the friend keyword inside the body of the class.
class className {
... .. ...
friend returnType functionName(arguments);
... .. ...
}

Example 1: Working of friend Function


// C++ program to demonstrate the working of friend function

#include <iostream>
using namespace std;

class Distance {
private:
int meter;
friend int addFive(Distance); // friend function
public:
Distance() : meter(0) {}

};

// friend function definition


int addFive(Distance d) {

//accessing private members from the friend function


d.meter += 5;
return d.meter;
}

int main() {
Distance D;
cout << "Distance: " << addFive(D);
return 0;
}
Output
Distance: 5
Here, addFive() is a friend function that can access both private and public data members.
Though this example gives us an idea about the concept of a friend function, it doesn't show any
meaningful use.
A more meaningful use would be operating on objects of two different classes. That's when the friend
function can be very helpful.

Example 2: Add Members of Two Different Classes


// Add members of two different classes using friend functions

#include <iostream>
using namespace std;

// forward declaration
class ClassB;

class ClassA {
public:
// constructor to initialize numA to 12
ClassA() : numA(12) {}

private:
int numA;
// friend function declaration
friend int add(ClassA, ClassB);
};

class ClassB {
public:
// constructor to initialize numB to 1
ClassB() : numB(1) {}

private:
int numB;

// friend function declaration


friend int add(ClassA, ClassB);
};

// access members of both classes


int add(ClassA objectA, ClassB objectB) {
return (objectA.numA + objectB.numB);
}
int main() {
ClassA objectA;
ClassB objectB;
cout << "Sum: " << add(objectA, objectB);
return 0;
}
Output
Sum: 13

In this program, ClassA and ClassB have declared add() as a friend function. Thus, this function can
access private data of both classes.
One thing to notice here is the friend function inside ClassA is using the ClassB. However, we haven't
defined ClassB at this point.
// inside classA
friend int add(ClassA, ClassB);
For this to work, we need a forward declaration of ClassB in our program.
// forward declaration
class ClassB;

friend Class in C++


We can also use a friend Class in C++ using the friend keyword. For example,
class ClassB;
class ClassA {
// ClassB is a friend class of ClassA
friend class ClassB;
... .. ...
}

class ClassB {
... .. ...
}
When a class is declared a friend class, all the member functions of the friend class become friend
functions.
Since ClassB is a friend class, we can access all members of ClassA from inside ClassB.
However, we cannot access members of ClassB from inside ClassA. It is because friend relation in
C++ is only granted, not taken.

Example 3: C++ friend Class


// C++ program to demonstrate the working of friend class

#include <iostream>
using namespace std;

// forward declaration
class ClassB;

class ClassA {
private:
int numA;

// friend class declaration


friend class ClassB;

public:
// constructor to initialize numA to 12
ClassA() : numA(12) {}
};

class ClassB {
private:
int numB;

public:
// constructor to initialize numB to 1
ClassB() : numB(1) {}

// member function to add numA


// from ClassA and numB from ClassB
int add() {
ClassA objectA;
return objectA.numA + numB;
}
};

int main() {
ClassB objectB;
cout << "Sum: " << objectB.add();
return 0;
}

Output
Sum: 13
Here, ClassB is a friend class of ClassA. So, ClassB has access to the members of classA.
In ClassB, we have created a function add() that returns the sum of numA and numB.
Since ClassB is a friend class, we can create objects of ClassA inside of ClassB.

Constructor and Destructor in C++


Constructor and Destructor are the special member functions of the class which are created by the
C++ compiler or can be defined by the user. Constructor is used to initialize the object of the class
while destructor is called by the compiler when the object is destroyed.
What is Constructor in C++?
A constructor is a special member function of a class and shares the same name as of class, which
means the constructor and class have the same name. Constructor is called by the compiler whenever
the object of the class is created, it allocates the memory to the object and initializes class data
members by default values or values passed by the user while creating an object. Constructors don’t
have any return type because their work is to just create and initialize an object.
What is the basic syntax of Constructor in C++?
The basic syntax of the constructor is given below:
class class_name{
private:
// private members
public:
// declaring constructor
class_name({parameters})
{
// constructor body
}
};
In the above syntax, we can see the class has the name class_name and the constructor have also the
same name. A constructor can have any number of parameters as per requirements. Also, there is no
return type or return value of the constructor.
Note: In the above syntax we have declared the constructor as a public member but we can declare it
private also (we will discuss that later in this article).
Important Points about Constructors
Access specifiers
Constructors can be defined as public, protected, or private as per the requirements. By default or
default constructors, which are created by the compiler are declared as the public. If the constructor
is created as private, then we are not able to create its object.
When there is no requirement of the object of a class (in a situation when all class members ar e
static) we can define its constructor as private.
Usually, constructors are defined as public because constructors are used to create an object and
initialize the class data members for the object. An object is always created from outside of class,
which justifies making constructors public.
Inheritance
As a derived class can access all the public properties of the base class, it can call its constructor also
if it is not declared as private. Also, the constructor's address cannot be referenced.
Virtual
Constructor in C++ cannot be declared as virtual because when we declare any function of a class as
a virtual function, at compile time compiler creates a virtual table to store the address of each
function that is declared as virtual. Also, it creates a data member of the class virtual pointer to
points towards the virtual table. But as we have discussed we cannot refer to the address of the
constructor, which means we are not able to declare the constructor as virtual.

How many types of Constructors are present in C++?


There are four types of constructors in c++
• Default constructor
• Parameterized constructor
• Copy Constructor
• Dynamic Constructor
Default Constructor
Default constructor is also known as a zero-argument constructor, as it doesn’t take any parameter. It
can be defined by the user if not then the compiler creates it on his own. Default constructor always
initializes data members of the class with the same value they were defined.
Syntax
class class_name{
private:
// private members
public:
// declaring default constructor
class_name()
{
// constructor body
}
};
Code to show the working of default constructor
#include <iostream>
using namespace std;
class Person{
// declaring private class data members
private:
string name;
int age;

public:
// declaring constructor
Person()
{
cout<<"Default constructor is called"<<endl;
name = "student";
age = 12;
}

// display function to print the class data members value


void display()
{
cout<<"Name of current object: "<<name<<endl;
cout<<"Age of current object: "<<age<<endl;
}
};
int main()
{
// creating object of class using default constructor
Person obj;
// printing class data members
obj.display();
return 0;
}
Output
Default constructor is called
Name of current object: student
Age of current object: 12

In the above code, we have created a class with two data members. Declared a default constructor
which always initializes objects of a class with the same name and age. In the main function, we
have created an object of the class and printed its data member values by using the display function.
Parameterized Constructor
Parameterized constructor is used to initialize data members with the values provided by the user.
This constructor is basically the upgraded version of the default constructor. We can define more
than one parameterized constructor according to the need of the user, but we have to follow the rules
of the function overloading, like a different set of arguments must be there for each constructor.
Syntax
class class_name{
private:
// private members
public:
// declaring parameterized constructor
class_name(parameter1, parameter2,...)
{
// constructor body
}
};

Code to understand the working of the parameterized constructor


#include <iostream>
using namespace std;
class Person{
// declaring private class data members
private:
string name;
int age;

public:
// declaring parameterized constructor of three different types
Person(string person_name)
{
cout<<"Constructor to set name is called"<<endl;
name = person_name;
age = 12;
}

Person(int person_age)
{
cout<<"Constructor to set age is called"<<endl;
name = "Student";
age = person_age;
}

Person(string person_name, int person_age)


{
cout<<"Constructor for both name and age is called"<<endl;
name = person_name;
age = person_age;
}
// display function to print the class data members value
void display()
{
cout<<"Name of current object: "<<name<<endl;
cout<<"Age of current object: "<<age<<endl;
cout<<endl;
}

};
int main()
{
// creating objects of class using parameterized constructor
Person obj1("First person");
// printing class data members for first object
obj1.display();

Person obj2(25);
// printing class data members for second object
obj2.display();

Person obj3("Second person",15);


// printing class data members for third object
obj3.display();
return 0;
}
Output
Constructor to set name is called
Name of current object: First person
Age of current object: 12

Constructor to set age is called


Name of current object: Student
Age of current object: 25

Constructor for both name and age is called


Name of current object: Second person
Age of current object: 15
In the above code, we have created three types of the parametric constructor, one for initialization of
name only, second to initialization of age only, and third to initialize both name and age. In the main
function, we have created three different types of objects and initialized them in different ways, and
printed values for each of them.

Copy Constructor
If we have an object of a class and we want to create its copy in a new declared object of the same
class, then a copy constructor is used. The compiler provides each class a default copy constructor
and users can define it also. It takes a single argument which is an object of the same class.
Syntax
class class_name{
private:
// private members
public:
// declaring copy constructor
class_name(const class_name& obj)
{
// constructor body
}
};
In the above syntax, we created a copy constructor which takes an object of the same class as a
parameter but it is declared constant and passed as a reference because when an argument is passed
as a function parameter it creates a copy for it, to create that copy compiler will again call the copy
constructor, means it will call the same function and for that call again there will be a call to create
copy which will take this process in neverending recursion of creating copies. To prevent such
conditions we pass it as a reference.

Code to understand the working of the copy constructor


#include <iostream>
using namespace std;
class Person{
// declaring private class data members
private:
string name;
int age;

public:
Person(string person_name, int person_age)
{
cout<<"Constructor for both name and age is called"<<endl;
name = person_name;
age = person_age;
}

Person(const Person& obj)


{
cout<<"Copy constructor is called"<<endl;
name = obj.name;
age = obj.age;
}
// display function to print the class data members value
void display()
{
cout<<"Name of current object: "<<name<<endl;
cout<<"Age of current object: "<<age<<endl;
cout<<endl;
}
};
int main()
{
// creating objects of class using parameterized constructor
Person obj1("First person",25);
// printing class data members for first object
obj1.display();
// creating copy of the obj1
Person obj2(obj1);
// printing class data members for second object
obj2.display();
return 0;
}
Output
Constructor for both name and age is called
Name of current object: First person
Age of current object: 25

Copy constructor is called


Name of current object: First person
Age of current object: 25
In the above code, we have created a class and defined two types of constructors in it, the first is a
parameterized constructor and another is a copy constructor. Parameterized constructor is used to
create an object then by using the copy constructor we create a copy of it and stored it in another
object.

A copy constructor is a special type of constructor in object-oriented programming languages like C++
and Java. It's used to create a new object as a copy of an existing object. This is particularly useful
when you want to create a copy of an object to perform operations without modifying the original
object.

In C++, a copy constructor is a constructor that takes a reference to an object of the same class as a
parameter. It initializes a new object by copying the contents of the passed object.

Here's an example of a copy constructor in C++:

#include <iostream>
using namespace std;
class MyClass {
private:
int data;

public:
// Constructor
MyClass(int val) : data(val) {}

// Copy Constructor
MyClass(const MyClass &obj) : data(obj.data) {}

// Getter method
int getData() const {
return data;
}
};
int main() {
// Create an object of MyClass
MyClass obj1(42);

// Use the copy constructor to create a copy of obj1


MyClass obj2 = obj1;

// Display data of both objects


cout << "Data in obj1: " << obj1.getData() << endl;
cout << "Data in obj2: " << obj2.getData() << endl;

return 0;
}

In this example:

• We have a class MyClass with a private data member data.


• We define a parameterized constructor that initializes data with the given value.
• We define a copy constructor that takes a reference to an object of MyClass as a parameter. It
initializes the data member of the new object with the value from the passed object.
• In the main function, we create an object obj1 of MyClass and initialize it with the value 42.
• Then, we use the copy constructor to create a new object obj2 and initialize it with obj1.
• We print the data stored in both objects to verify that obj2 is indeed a copy of obj1.

Copy constructors are automatically called when an object is passed by value to a function, returned by
value from a function, or when an object is explicitly initialized with another object. They ensure that
the new object is a deep copy of the original object, preventing issues related to shallow copying.

Dynamic Constructor
When memory is allocated dynamically to the data members at the runtime using a new operator, the
constructor is known as the dynamic constructor. This constructor is similar to the default or
parameterized constructor; the only difference is it uses a new operator to allocate the memory.
Syntax
class class_name{
private:
// private members

public:

// declaring dynamic constructor


class_name({parameters})
{
// constructor body where data members are initialized using new operator
}

};
Code to understand the working of the dynamic constructor
#include <iostream>
using namespace std;

class Person{

// declaring private class data members


private:
int* age;
public:
Person(int* person_age)
{
cout<<"Constructor for age is called"<<endl;

// allocating memory
age = new int;
age = person_age;
}

// display function to print the class data members value


void display()
{
cout<<"Age of current object: "<<*age<<endl;
cout<<endl;
}

};
int main()
{
// creating objects of class using parameterized constructor
int age = 25;
Person obj1(&age);

// printing class data members for first object


obj1.display();

return 0;
}
Output
Constructor for age is called
Age of current object: 25
In the above code, we have created a class with a dynamic constructor. In the main function, we
have created an object and initialized it using a dynamic constructor, where we have given memory
dynamically using a new operator.
What is Destructor in C++?
Destructor is just the opposite function of the constructor. A destructor is called by the compiler
when the object is destroyed and its main function is to deallocate the memory of the object. The
object may be destroyed when the program ends, or local objects of the function get out of scope
when the function ends or in any other case.
Destructor has the same as of the class with prefix tilde(~) operator and it cannot be overloaded as
the constructor. Destructors take no argument and have no return type and return value.
The basic syntax of the Destructor is given below
class class_name{
private:
// private members
public:
// declaring destructor
~class_name()
{
// destructor body
}
};
In the above syntax, we can see the class has the name class_name and the destructor also has the
same name, in addition there is a tilde(~). Also, there is no return type and return value of the
destructor.
Note: In the above syntax we have declared the destructor as a public member but we can declare it
private also.
Important Points about the Destructor

• Destructor are the last member function called for an object and they are called by the
compiler itself.
• If the destructor is not created by the user then compile creates or declares it by itself.
• A Destructor can be declared in any section of the class, as it is called by the compiler so
nothing to worry about.
• As Destructor is the last function to be called, it should be better to declare it at the end of the
class to increase the readability of the code.
• Destructor is just the opposite of the constructor as the constructor is called at the time of the
creation of the object and allocates the memory to the object, on the other side the destructor
is called at the time of the destruction of the object and deallocates the memory.
How Constructor and Destructor are called when the object is Created and Destroyed
As constructor is the first function called by the compiler when an object is created and the
destructor is the last class member called by the compiler for an object. If the constructor and
destructor are not declared by the user, the compiler defines the default constructor and destructor of
a class object.

Let’s see a code to get the proper idea of how constructor and destructor are called:
First, we will create a class with single parametrized constructors and a destructor. Both of them
contain print statements to give an idea of when they are called.
#include <iostream>
using namespace std;

class class_name{

// declaring private class data members


private:
int a,b;

public:

// declaring Constructor
class_name(int aa, int bb)
{
cout<<"Constructor is called"<<endl;
a = aa;
b = bb;

cout<<"Value of a: "<<a<<endl;
cout<<"Value of b: "<<b<<endl;
cout<<endl;
}

// declaring destructor
~class_name()
{
cout<<"Destructor is called"<<endl;
cout<<"Value of a: "<<a<<endl;
cout<<"Value of b: "<<b<<endl;
}

};
int main()
{
// creating objects of class using parameterized constructor
class_name obj(5,6);

return 0;
}
Output
Constructor is called
Value of a: 5
Value of b: 6

Destructor is called
Value of a: 5
Value of b: 6
In the above code, we have created a class with constructor and destructor. In the main function, an
object uses a parametric constructor, and when the program ends the destructor is automatically
called by the compiler and we get the values of our variables.
Conclusion

• Constructor and Destructor are the special member functions of the class which are created
by the C++ compiler or can be defined by the user.
• Constructor is called by the compiler whenever the object of the class is created, it allocates
the memory to the object and initializes class data members.
• A destructor is called by the compiler when the object is destroyed and its main function is to
deallocate the memory of the object.
• Constructors have the same as of class while destructors have the same name of the class
with the prefix a tilde (~) operator.
• Both Constructor and destructor can be defined as public, private, or protected. But it is
better to declare the constructor as public.
• The constructor can have parameters but the destructor doesn’t receive any parameters.

Example/Implementation of Constructor and Destructor:

#include <iostream> {
using namespace std; cout<<"Destructor called"<<endl;
}
class Z };
{
public: int main()
// constructor {
Z() Z z1; // Constructor Called
{ int a = 1;
cout<<"Constructor called"<<endl; if(a==1)
} {
Z z2; // Constructor Called
// destructor } // Destructor Called for z2
~Z() } // Destructor called for z1

Output:
Constructor called
Constructor called
Destructor called
Destructor called
Difference between Constructor and Destructor in C++ :
S.
No. Constructor Destructor

Constructor helps to initialize the object of a Whereas destructor is used to destroy


1.
class. the instances.

It is declared as className( arguments if Whereas it is declared as ~


2.
any ){Constructor’s Body }. className( no arguments ){ }.

Constructor can either accept arguments or


3. While it can’t have any arguments.
not.

A constructor is called when an instance or It is called while object of the class is


4.
object of a class is created. freed or deleted.

Constructor is used to allocate the memory to While it is used to deallocate the


5.
an instance or object. memory of an object of a class.

6. Constructor can be overloaded. While it can’t be overloaded.

Here, its name is also same as the


The constructor’s name is same as the class
7. class name preceded by the tiled (~)
name.
operator.

While in a class, there is always a


8. In a class, there can be multiple constructors.
single destructor.

There is a concept of copy constructor which


While here, there is no copy
9. is used to initialize an object from another
destructor concept.
object.

They are often called in reverse order


10. They are often called in successive order.
of constructor.

Instantiation of Objects:
In C++, instantiation refers to the process of creating an instance (or object) of a class. When
you define a class in C++, you're essentially defining a blueprint or a template for creating
objects. Instantiation involves creating an actual object based on this blueprint.
instantiation in C++ is the process of creating an actual object of a class, which can then be used
to access its members and methods. Each object created from the class has its own set of data
members and methods, but they all share the same structure defined by the class.

Default Arguments in C++


A default argument is a value provided in a function declaration that is automatically assigned
by the compiler if the calling function doesn’t provide a value for the argument. In case any
value is passed, the default value is overridden.
1) The following is a simple C++ example to demonstrate the use of default arguments. Here, we
don’t have to write 3 sum functions; only one function works by using the default values for 3rd
and 4th arguments.

CPP Program to demonstrate Default Arguments


#include <iostream>
using namespace std;

// A function with default arguments, it can be called with 2 arguments or 3 arguments or 4


arguments.
int sum(int x, int y, int z = 0, int w = 0) //assigning default values to z,w as 0
{
return (x + y + z + w);
}

int main()
{

cout << sum(10, 15) << endl;

cout << sum(10, 15, 25) << endl;

cout << sum(10, 15, 25, 30) << endl;


return 0;
}

Output
25
50
80
Explanation: In statement 1, only two values are passed, hence the variables z and w take the
default values of 0. In statement 2, three values are passed, so the value of z is overridden with
25. In statement 3, four values are passed, so the values of z and w are overridden with 25 and
30 respectively.

2) If function overloading is done containing the default arguments, then we need to make sure it
is not ambiguous to the compiler, otherwise it will throw an error. The following is the modified
version of the above program.

// CPP Program to demonstrate Function overloading in Default Arguments


#include <iostream>
using namespace std;

// A function with default arguments, it can be called with 2 arguments or 3 arguments or 4


arguments.
int sum(int x, int y, int z = 0, int w = 0)
{
return (x + y + z + w);
}
int sum(int x, int y, float z = 0, float w = 0)
{
return (x + y + z + w);
}
// Driver Code
int main()
{
cout << sum(10, 15) << endl;
cout << sum(10, 15, 25) << endl;
cout << sum(10, 15, 25, 30) << endl;
return 0;
}

Error:
prog.cpp: In function 'int main()':
prog.cpp:17:20: error: call of overloaded
'sum(int, int)' is ambiguous
cout << sum(10, 15) << endl;
^
prog.cpp:6:5: note: candidate:
int sum(int, int, int, int)
int sum(int x, int y, int z=0, int w=0)
^
prog.cpp:10:5: note: candidate:
int sum(int, int, float, float)
int sum(int x, int y, float z=0, float w=0)
^
3) A constructor can contain default parameters as well. A default constructor can either have no
parameters or parameters with default arguments.

// CPP code to demonstrate use of default arguments in Constructors

#include <iostream>
using namespace std;

class A {
private:
int var = 0;
public:
A(int x = 0): var(x){}; // default constructor with one argument
// Note that var(x) is the syntax in c++ to do : "var = x"
void setVar(int s){
var = s; // OR => this->var = s;
return;
}
int getVar(){
return var; // OR => return this->var;
}
};
int main(){
A a(1);
a.setVar(2);

cout << "var = " << a.getVar() << endl;

/* ANOTHER APPROACH:
A *a = new A(1);

a->setVar(2);

cout << "var = " << a->getVar() << endl;


*/
}

// contributed by Francisco Vargas #pt

Explanation: Here, we see a default constructor with no arguments and a default constructor
with one default argument. The default constructor with argument has a default parameter x,
which has been assigned a value of 0.
Key Points:
• Default arguments are different from constant arguments as constant arguments can’t
be changed whereas default arguments can be overwritten if required.
• Default arguments are overwritten when the calling function provides values for
them. For example, calling the function sum(10, 15, 25, 30) overwrites the values of
z and w to 25 and 30 respectively.
• When a function is called, the arguments are copied from the calling function to the
called function in the order left to right. Therefore, sum(10, 15, 25) will assign 10,
15, and 25 to x, y, and z respectively, which means that only the default value of w is
used.
• Once a default value is used for an argument in the function definition, all subsequent
arguments to it must have a default value as well. It can also be stated that the default
arguments are assigned from right to left. For example, the following function
definition is invalid as the subsequent argument of the default variable z is not
default.
// Invalid because z has default value, but w after it doesn't have a default value
int sum(int x, int y, int z = 0, int w).
Advantages of Default Arguments:
• Default arguments are useful when we want to increase the capabilities of an existing
function as we can do it just by adding another default argument to the function.
• It helps in reducing the size of a program.
• It provides a simple and effective programming approach.
• Default arguments improve the consistency of a program.
Disadvantages of Default Arguments:
• It increases the execution time as the compiler needs to replace the omitted
arguments by their default values in the function call.

How memory is allocated when an object/variable is created!!!


When a C++ program is compiled, memory allocation for objects typically occurs in the
following manner:
1. Static Memory Allocation: For objects declared as global variables or static variables,
memory is allocated at compile-time. These variables have fixed memory addresses
determined during the compilation process, and their memory is allocated in a region
known as the data segment or BSS segment of the program's memory space.
2. Stack Memory Allocation: For objects declared within a function or block scope (local
variables), memory is typically allocated on the stack. The stack is a region of memory
that is used for storing function call frames and local variables. Memory allocation on the
stack is managed automatically by the compiler and is typically fast and efficient. When
a function is called, space is allocated on the stack for its local variables, and when the
function returns, that space is automatically deallocated.
3. Dynamic Memory Allocation: Objects that are allocated dynamically using operators
such as `new` or `malloc()` in C++, or using memory allocation functions provided by
the operating system, are allocated memory from the heap. The heap is a region of
memory that is managed by the operating system, and memory allocation and
deallocation occur at runtime. When an object is dynamically allocated, space is
allocated from the heap, and a pointer to that memory location is returned. The
programmer is responsible for explicitly deallocating this memory when it is no longer
needed, typically using `delete` in C++ or `free()` in C.
It's important to note that the specifics of memory allocation may vary depending on the
compiler and the target platform. Additionally, the C++ standard library provides memory
management utilities such as smart pointers (`std::shared_ptr`, `std::unique_ptr`) which automate
memory management to some extent and can be used to manage dynamically allocated memory
more safely than raw pointers.

new and delete Operators in C++ For Dynamic Memory



Dynamic memory allocation in C/C++ refers to performing memory allocation manually by a
programmer. Dynamically allocated memory is allocated on Heap, and non-static and local
variables get memory allocated on Stack.

What are applications?


• One use of dynamically allocated memory is to allocate memory of variable size, which
is not possible with compiler allocated memory except for variable-length arrays.
• The most important use is the flexibility provided to programmers. We are free to
allocate and deallocate memory whenever we need it and whenever we don’t need it
anymore. There are many cases where this flexibility helps. Examples of such cases
are Linked List, Tree, etc.
How is it different from memory allocated to normal variables?
For normal variables like “int a”, “char str[10]”, etc, memory is automatically allocated and
deallocated. For dynamically allocated memory like “int *p = new int[10]”, it is the programmer’s
responsibility to deallocate memory when no longer needed. If the programmer doesn’t deallocate
memory, it causes a memory leak (memory is not deallocated until the program terminates).

How is memory allocated/deallocated in C++?


C uses the malloc() and calloc() function to allocate memory dynamically at run time and uses a
free() function to free dynamically allocated memory. C++ supports these functions and also has
two operators new and delete, that perform the task of allocating and freeing the memory in a
better and easier way.

new operator
The new operator denotes a request for memory allocation on the Free Store. If sufficient memory
is available, a new operator initializes the memory and returns the address of the newly allocated
and initialized memory to the pointer variable.
Syntax to use new operator
pointer-variable = new data-type;
Here, the pointer variable is the pointer of type data-type. Data type could be any built-in data type
including array or any user-defined data type including structure and class.
Example:
// Pointer initialized with NULL Then request memory for the variable
int *p = NULL;
p = new int;

OR

// Combine declaration of pointer and their assignment


int *p = new int;

Initialize memory: We can also initialize the memory for built-in data types using a new operator.
For custom data types, a constructor is required (with the data type as input) for initializing the
value. Here’s an example of the initialization of both data types :
pointer-variable = new data-type(value);
Example:

int* p = new int(25);


float* q = new float(75.25);
// Custom data type
struct cust
{
int p;
cust(int q) : p(q) {}
cust() = default;
//cust& operator=(const cust& that) = default;
};
int main()
{
// Works fine, doesn’t require constructor
cust* var1 = new cust;
//OR
// Works fine, doesn’t require constructor
var1 = new cust();
// Notice error if you comment this line
cust* var = new cust(25);
return 0;
}
Allocate a block of memory: a new operator is also used to allocate a block(an array) of memory
of type data type.
pointer-variable = new data-type[size];
where size(a variable) specifies the number of elements in an array.
Example:
int *p = new int[10]
Dynamically allocates memory for 10 integers continuously of type int and returns a pointer to the
first element of the sequence, which is assigned top(a pointer). p[0] refers to the first element, p[1]
refers to the second element, and so on.

Normal Array Declaration vs Using new


There is a difference between declaring a normal array and allocating a block of memory using
new. The most important difference is, that normal arrays are deallocated by the compiler (If the
array is local, then deallocated when the function returns or completes). However, dynamically
allocated arrays always remain there until either they are deallocated by the programmer or the
program terminates.

What if enough memory is not available during runtime?


If enough memory is not available in the heap to allocate, the new request indicates failure by
throwing an exception of type std::bad_alloc, unless “nothrow” is used with the new operator, in
which case it returns a NULL pointer (scroll to section “Exception handling of new operator”
in this article). Therefore, it may be a good idea to check for the pointer variable produced by the
new before using its program.
int *p = new(nothrow) int;
if (!p)
{
cout << "Memory allocation failed\n";
}
delete operator
Since it is the programmer’s responsibility to deallocate dynamically allocated memory,
programmers are provided delete operator in C++ language.
Syntax:
// Release memory pointed by pointer-variable
delete pointer-variable;
Here, the pointer variable is the pointer that points to the data object created by new.

Examples:
delete p;
delete q;
To free the dynamically allocated array pointed by pointer variable, use the following form
of delete:
// Release block of memory
// pointed by pointer-variable
delete[] pointer-variable;

Example:

// It will free the entire array pointed by p.


delete[] p;

// C++ program to illustrate dynamic allocation and deallocation of memory using new and
delete
#include <iostream>
using namespace std;
int main ()
{
// Pointer initialization to null
int* p = NULL;
// Request memory for the variable using new operator
p = new(nothrow) int;
if (!p)
cout << "allocation of memory failed\n";
else
{
// Store value at allocated address
*p = 29;
cout << "Value of p: " << *p << endl;
}
// Request block of memory using new operator
float *r = new float(75.25);
cout << "Value of r: " << *r << endl;
// Request block of memory of size n
int n = 5;
int *q = new(nothrow) int[n];
if (!q)
cout << "allocation of memory failed\n";
else
{
for (int i = 0; i < n; i++)
q[i] = i+1;
cout << "Value store in block of memory: ";
for (int i = 0; i < n; i++)
cout << q[i] << " ";
}
// freed the allocated memory
delete p;
delete r;
// freed the block of allocated memory
delete[] q;
return 0;
}

Output
Value of p: 29
Value of r: 75.25
Value store in block of memory: 1 2 3 4 5
GRABAGE COLLECTION:
Garbage collection is a memory management technique used in programming languages to
automatically reclaim memory occupied by objects that are no longer in use by the program.
The garbage collection process typically involves identifying memory that is no longer reachable
or referenced by the program, and then reclaiming that memory for future use. This is done by
periodically scanning the heap (the region of memory used for dynamic memory allocation) to
identify objects that are no longer reachable from any live references or pointers in the program.
Why we need garbage collectors??
Our programs involve memory, in the form of variables and objects. Objects are allocated on
either the Stack or the Heap. Stacks store locally declared variables like “int a = 10;” on the stack
frame of a function, so when the function returns values are popped from the stacked frame
rendering them non-existent. So we do not need garbage collection for the stack.
Heaps on the other hand are different. A heap variable is allocated using “new” or “malloc”
functions. The object space created for such things is in RAM. They must be explicitly freed
when we are finished with them as they outlive the function scope and execution. For heaps, we
need an automatic memory recovery feature built into programming languages called garbage
collectors. The absence of a garbage collector can lead to Memory Leaks and Dangling Pointers.
Why C/C++ lacks garbage collection?
1. Performance: Garbage collection can be resource-intensive and can negatively impact
the performance of a program. In C/C++, developers have the ability to manually
manage memory, which can result in more efficient use of resources. C/C++ must be
able to run on bare metals with fast runtime.

2. Control: C/C++ allows developers to have full control over the allocation and
deallocation of memory, allowing them to optimize their code for specific use cases.
With garbage collection, developers may not have as much control over the
allocation and deallocation of memory.

3. Compatibility: C/C++ is often used to write low-level system libraries and drivers,
which require precise control over memory management. Garbage collection may not
be compatible with these types of applications.

4. Complexity: Implementing garbage collection in C/C++ can be complex, as it


requires adding additional code to the language. This can increase the complexity of
the language and may not be worth the effort for some developers.

5. Legacy code: C/C++ has been around for a long time and has a large number of
existing code bases that rely on manual memory management. Adding garbage
collection to the language could potentially break these code bases and cause
problems for developers who rely on them.

Can we build one?

Yes, it is possible to build a garbage collection system for C/C++. There are several third-party
libraries that offer garbage collection for C/C++, such as the Boehm-Demers-Weiser garbage
collector. However, these systems may not work with all C/C++ code and may have some
performance overhead compared to manual memory management. Additionally, implementing
garbage collection in C/C++ may be more complex and require more effort than in languages that
have native support for garbage collection.

In C and C++, you can implement garbage collection using reference counting,mark-and-sweep,
tracing garbage collection etc.

You might also like