0% found this document useful (0 votes)
20 views164 pages

C

Uploaded by

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

C

Uploaded by

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

C++ vs Java

Performance Considerations

1. Direct Compilation to Machine Code (C++):

 Since C++ code is compiled directly to machine code, it can take full
advantage of the hardware, leading to potentially better performance.
 Optimizations performed by the compiler can significantly enhance
execution speed.

2. Bytecode and JIT Compilation (Java):

 Initially, Java's bytecode was interpreted, which made it slower than


compiled languages like C++.
 Modern JVMs use JIT compilation, which compiles bytecode into machine
code at runtime. This can result in performance that is closer to compiled
languages.
 The JIT compiler can optimize code based on runtime behavior, which can
lead to performance improvements over time.

3. Garbage Collection:

 Java uses automatic garbage collection to manage memory, which can


introduce overhead and affect performance.
 C++ requires manual memory management, giving developers more
control over performance but also introducing the risk of memory leaks
and other issues.

4. Language Features and Standard Libraries:

 C++ allows for low-level manipulation and direct memory access, which
can lead to more efficient code.
 Java provides a rich set of high-level APIs and abstractions, which can
simplify development but may introduce performance overhead.

Real-World Performance
 In practice, the performance difference between C++ and Java depends
on various factors, including the nature of the application, the efficiency of
the algorithms used, and the quality of the code.
 For compute-intensive tasks and systems programming, C++ is often
preferred due to its potential for higher performance.
 For applications where development speed, portability, and ease of
maintenance are more critical, Java might be chosen despite the possible
performance trade-offs.

Conclusion
While it is generally true that C++ can be faster than Java due to its direct
compilation to machine code, the actual performance difference can vary
significantly based on the context. Modern advancements in JVM
technology, particularly JIT compilation, have closed much of the
performance gap between Java and traditionally compiled languages like
C++. Therefore, the choice between C++ and Java should consider not
only raw performance but also factors such as development time,
maintainability, and the specific requirements of the application.

Bytecode vs machine code:

Certainly! Let's delve into the differences between bytecode and machine
code, as they are crucial concepts in understanding how various
programming languages, including Java, are executed.

Bytecode

1. Definition:

 Bytecode is an intermediate, platform-independent code generated by the


compiler of certain programming languages (such as Java).
 It is a low-level code that is more abstract than machine code.
2. Execution:

 Bytecode is not executed directly by the hardware.


 Instead, it is executed by a virtual machine (VM) such as the Java Virtual
Machine (JVM).
 The VM interprets or compiles the bytecode into machine code that can be
executed by the computer's CPU.

3. Portability:

 Bytecode is designed to be portable across different platforms. This


means the same bytecode can run on any system that has the
appropriate VM.
 This is a key feature of languages like Java, enabling the "write once, run
anywhere" philosophy.

4. Examples:

 Java bytecode, produced by the javac compiler from Java source code.
 Bytecode for other languages such as Python (Pyc files).

Machine Code

1. Definition:

 Machine code is the lowest-level code that is directly executed by a


computer's CPU.
 It consists of binary instructions specific to the architecture of the CPU
(e.g., x86, ARM).

2. Execution:

 Machine code is executed directly by the hardware without any further


translation or interpretation.
 This allows for very fast execution, as there is no intermediate layer
between the code and the hardware.

3. Portability:

 Machine code is not portable. It is specific to a particular CPU architecture.


 Code compiled for one type of CPU will not run on another type without
recompilation.

4. Examples:

 The binary executable files produced by a C++ compiler.


 Assembly language code assembled into machine code.

Key Differences

1. Level of Abstraction:

 Bytecode: More abstract, designed to be interpreted or compiled by a


virtual machine.
 Machine Code: Low-level, directly executed by the CPU.

2. Portability:

 Bytecode: Platform-independent; can run on any system with the


appropriate virtual machine.
 Machine Code: Platform-dependent; specific to a particular CPU
architecture.

3. Execution:

 Bytecode: Executed by a virtual machine, which can interpret or JIT


compile it to machine code.
 Machine Code: Directly executed by the CPU.

4. Use Case:

 Bytecode: Used in languages and environments that prioritize portability


(e.g., Java, Python).
 Machine Code: Used in scenarios where performance is critical, and the
code needs to run directly on the hardware (e.g., system programming
with C or C++).

Summary
 Bytecode: Intermediate, portable code that is executed by a virtual
machine.
 Machine Code: Low-level, non-portable code that is executed directly by
the CPU.
Understanding these differences helps clarify how languages like Java
achieve portability and flexibility, whereas languages like C++ prioritize
performance and direct hardware interaction.

Feature C++ Java


Language Type Compiled Compiled to bytecode; executed by JVM
Bytecode interpreted/JIT-compiled by
Execution Directly executed as machine code JVM
Platform
Dependency Platform-dependent Platform-independent (JVM-based)
Memory
Management Manual (new/delete) Automatic (Garbage Collection)
Performance Typically faster Generally slower due to JVM overhead
Complex with pointers and manual
Syntax memory Simpler, no pointers
Standard Library Extensive, including STL Rich standard library (Java API)
Single inheritance (interfaces for
Inheritance Multiple inheritance multiple)
Pointers Yes No (references instead)
Concurrency Low-level (pthread, etc.) High-level (java.util.concurrent)
Exception
Handling Optional Mandatory
Operator
Overloading Yes No
Template/Generics Templates Generics
Memory Safety Prone to issues (e.g., memory leaks) Safer (managed by JVM)
System programming, game
Use Cases development Web applications, enterprise solutions
Compilation Time Generally longer Generally shorter
Learning Curve Steeper Gentler
Development Faster due to automatic memory
Speed Slower due to manual management management

Running of c++ program::

Before the main function is called, the C++ compiler performs several tasks, including:
Preprocessing: The C++ preprocessor processes all of the preprocessor directives in the
program, such as "#include" and "#define". These directives are replaced with the contents of
the included files or the defined constants.

Compiling: The C++ compiler translates the preprocessed source code into machine code,
which is a low-level code that can be executed by the computer's processor.

Linking: The linking process combines the compiled object files and any external libraries
used by the program into a single executable file.

Once the program has been compiled and linked, it can be run. The program will start
executing at the main function and will continue to execute the code within the main function
until it reaches the end. The main function must return an integer value to indicate the success
or failure of the program.

Basic Terminology:

1. Keywords: Keywords are predefined words in a programming


language that has special meaning and cannot be used as a variable
name or function name. Examples of keywords in C++ include "int",
"float", "while", and "for".

2. Variables: Variables are named storage locations in a program that


can hold a value of a particular data type. In C++, variables must be
declared with a specific data type before they can be used. Examples of
data types in C++ include "int" for integers, "float" for decimal numbers,
and "char" for characters.

3. Functions: Functions are self-contained blocks of code that perform a


specific task. In C++, functions must be declared before they can be
used. Functions can take input parameters and return a result.

4. Object Oriented Programming (OOP): OOP is a programming


paradigm that organizes code into objects that represent real-world
entities. These objects can have attributes (variables) and behaviors
(functions). OOP languages, such as C++, allow for the creation of
classes, which are templates for objects.

5. Statically Typed Languages: Statically typed languages are those in


which the type of a variable must be declared at the time of its creation
and cannot be changed later. C++ is a statically typed language.
6. Dynamically Typed Languages: Dynamically typed languages are
those in which the type of a variable is not declared at the time of its
creation and can be changed later. Examples of dynamically typed
languages include Python and Ruby.

7. Header Files: Header files in C++ are files that contain declarations
for functions, variables, and other constructs that can be included in a C+
+ program using the preprocessor directive "#include". These
declarations allow the program to use the functions and variables defined
in the header file without having to know their implementation details.

8. Namespace: A namespace in C++ is a container for a set of identifiers


(variables, functions, etc.) that helps to prevent naming conflicts in large
programs. Namespaces are declared using the "namespace" keyword and
can be referenced using the "::" operator.

Feature Visual Studio Visual Studio Code


Integrated Development Environment
Type (IDE) Source Code Editor
Primary Use Full-scale development with project
Case management Lightweight editing and coding
Platform Windows, macOS Windows, macOS, Linux
Supported C++, C#, F#, VB.NET, Python, JavaScript, TypeScript, Python, C++,
Languages JavaScript, and more Java, and more
Installation
Size Large, with many components and tools Lightweight, smaller footprint
Performance Resource-intensive Fast and lightweight
Supports complex project and solution
Project System management Folder-based project structure
Debugging Advanced debugging capabilities Built-in debugging with extensions
Extensive marketplace for plugins and
Extensions tools Large extension marketplace
Highly customizable with various Highly customizable with JSON
Customization settings configuration files
Version Control Integrated Git, TFVC, and other VCS Integrated Git support
Build and Built-in build and deployment tools for Relies on external tools and extensions
Deployment various platforms for build tasks
Includes tools for application lifecycle Focuses on individual development,
Enterprise management, code quality, and though extensions can add enterprise
Features collaboration capabilities
Community edition is free; Professional
Cost and Enterprise editions are paid Free and open-source
Advanced IntelliSense and code
IntelliSense navigation IntelliSense and basic code navigation
Understanding object-oriented programming allows you to develop a way
of thinking and implementing code. After all, one of the main reasons why
we code or at least want to learn how to do so is to automate routine
tasks. O.O.P. serves as a trick to achieve this purpose.

Object-oriented programming uses predefined programming modular


units (objects, classes, subclasses, and so forth) in order to make
programming faster and easier to maintain. Object-oriented languages
help to manage complexity in large programs.

Objects package data and the operations on them so that only the
operations are publicly accessible and internal details of the data
structures are hidden. This information hiding made large-scale
programming easier by allowing a programmer to think about each part of
the program in isolation.

In addition, objects may be derived from more general ones, “inheriting”


their capabilities. Such an object hierarchy made it possible to define
specialized objects without repeating all that is in the more general ones.

OOP stands for Object-Oriented Programming.

Procedural programming is about writing procedures or functions that


perform operations on the data, while object-oriented programming is about
creating objects that contain both data and functions.
Object-oriented programming has several advantages over procedural
programming:

 OOP is faster and easier to execute


 OOP provides a clear structure for the programs
 OOP helps to keep the C++ code DRY "Don't Repeat Yourself", and
makes the code easier to maintain, modify and debug
 OOP makes it possible to create full reusable applications with less
code and shorter development time

From bard::
Object-oriented programming (OOP) offers several significant advantages in C++ compared
to procedural programming, making it a powerful paradigm for structuring complex software:

1. Improved Code Organization and Maintainability:

 Real-World Modeling: OOP allows you to create objects that represent real-world
entities, like Car, BankAccount, or Window. This makes code more intuitive and easier
to understand, especially for larger projects.
 Modularization: Classes encapsulate data (properties) and the functions (methods)
that operate on that data. This modularity promotes better code organization and
reusability. Changes made to a class are less likely to affect other parts of your
program, improving maintainability.

2. Code Reusability and Reduced Redundancy:

 Inheritance: OOP allows you to create new classes (subclasses) that inherit
properties and behaviors from existing classes (base classes). This eliminates the need
to rewrite common code, saving development time and effort. Imagine a base class
Vehicle with properties like color and speed, and derived classes Car and Truck
inheriting these while adding their specific functionalities.
 Polymorphism: Objects of different classes (derived from a common base) can
respond differently to the same message (function call). This flexibility allows you to
write generic code that works with various object types without extensive
modifications. For instance, a printInfo function could handle both Car and Truck
objects appropriately.

3. Encapsulation and Data Protection:

 Data Hiding: OOP promotes data hiding by restricting direct access to an object's
internal data (attributes) through private members. Public member functions
(methods) provide controlled access and modification of data, ensuring data integrity
and preventing accidental errors.

4. Improved Problem-Solving with Abstraction:


 Focus on Objects: You can focus on the behavior and interactions of objects rather
than the underlying implementation details. This simplifies problem-solving by
breaking down complex tasks into smaller, manageable units.

Feature C++ Python


High performance, suitable for Moderate performance, often sufficient for
system-level and performance-critical many applications; can use libraries written
Performance applications in C/C++ for critical tasks
Complex syntax with many features
like pointers and manual memory Simple and clean syntax, emphasizing
Syntax management readability and ease of use
Steeper learning curve, requires more
code to achieve the same Beginner-friendly, allows rapid development
Ease of Use functionality with fewer lines of code
Compiled language, requires
compilation to machine code before Interpreted language, executed by an
Compilation execution interpreter at runtime
Memory Manual memory management, offers Automatic memory management with
Management control but increases risk of errors garbage collection
Development Slower development cycle due to Fast development cycle, ideal for
Speed complexity and compilation steps prototyping and iterative development
Rich set of libraries for system-level Vast ecosystem of libraries for web
Libraries & programming, game development, development, data science, machine
Ecosystem etc. learning, etc.
Community & Long-established, active community Rapidly growing community with abundant
Support with extensive resources resources and tutorials
System/software development, game
development, real-time simulation, Web development, data science, AI/ML,
Use Cases embedded systems automation, scripting
Can be integrated with other Known for easy integration with other
Interoperabilit languages, but often requires languages and tools, commonly used as a
y additional tools scripting language
Compile-time type checking helps Run-time type checking, more flexible but
Error Handling catch errors early can lead to run-time errors
Highly portable, can be used on
various platforms with platform- Highly portable, runs on virtually any
Portability specific adjustments platform with a Python interpreter
Supports multiple concurrency Multithreading support with the Global
models including multithreading and Interpreter Lock (GIL); better concurrency
Concurrency multiprocessing with multiprocessing
Steep, due to complex syntax and
Learning Curve concepts Gentle, due to simple and readable syntax

While C++ can be used procedurally, OOP offers a more structured and efficient
approach for building large-scale applications, especially those involving complex
interactions and data management.
Feature Scripting Language General-Purpose Language
Execution Interpreted Compiled (often)
Syntax Simple and easy to learn Complex, with rich features
Development
Speed Fast development and iteration Typically slower due to compilation
Performance Generally slower Optimized for high performance
Memory Manual or automatic depending on the
Management Automatic (garbage collection) language
Automation, web scripting, quick
Use Cases tasks System software, applications, games
Acts as glue code for other Can be integrated but often as the main
Integration systems system
Typical Languages Python, JavaScript, Ruby C++, Java, C#

Scripting Language
Definition: A scripting language is designed for integrating and
communicating with other programming languages and for automating
repetitive tasks. Scripts are usually interpreted rather than compiled.

All scripting languages are programming languages. The scripting


language is basically a language where instructions are written for a run
time environment. They do not require the compilation step and are rather
interpreted. It brings new functions to applications and glue complex
system together. A scripting language is a programming language
designed for integrating and communicating with other programming
languages.
Scripting languages are a subset of programming languages designed for
specific run-time environments to automate tasks, control software applications,
and integrate different system components. Unlike compiled languages, scripting
languages are typically interpreted, meaning the code is executed directly by an
interpreter without a prior compilation step.

Variables in C++ is a name given to a memory location. It is the basic unit


of storage in a program.

 The value stored in a variable can be changed during program


execution.
 A variable is only a name given to a memory location, all the
operations done on the variable effects that memory location.
 In C++, all the variables must be declared before use.
A typical variable declaration is of the form:

// Declaring a single variable


type variable_name;

// Declaring multiple variables:


type variable1_name, variable2_name, variable3_name;

Types of Variables
There are three types of variables based on the scope of variables in C++

 Local Variables
 Instance Variables
 Static Variables

1. Local Variables: A variable defined within a block or method or constructor is called a local
variable.
o These variables are created when entered into the block or the function is called and
destroyed after exiting from the block or when the call returns from the function.
o The scope of these variables exists only within the block in which the variable is
declared. i.e. we can access this variable only within that block.
o Initialization of Local Variable is Mandatory.
2. Instance Variables: Instance variables are non-static variables and are declared in a class
outside any method, constructor, or block.
o As instance variables are declared in a class, these variables are created when an
object of the class is created and destroyed when the object is destroyed.
o Unlike local variables, we may use access specifiers for instance variables. If we do
not specify any access specifier then the default access specifier will be used.
o Initialization of Instance Variable is not Mandatory.
o Instance Variable can be accessed only by creating objects.
3. Static Variables: Static variables are also known as Class variables.
o These variables are declared similarly as instance variables, the difference is that
static variables are declared using the static keyword within a class outside any
method constructor or block.
o Unlike instance variables, we can only have one copy of a static variable per class
irrespective of how many objects we create.
o Static variables are created at the start of program execution and destroyed
automatically when execution ends.
o Initialization of Static Variable is not Mandatory. Its default value is 0
o If we access the static variable like the Instance variable (through an object), the
compiler will show the warning message and it won’t halt the program. The compiler
will replace the object name with the class name automatically.
o If we access the static variable without the class name, the Compiler will
automatically append the class name.
Instance Variable Vs Static Variable
 Each object will have its own copy of the instance variable whereas We can only have one
copy of a static variable per class irrespective of how many objects we create.
 Changes made in an instance variable using one object will not be reflected in other objects
as each object has its own copy of the instance variable. In the case of static, changes will be
reflected in other objects as static variables are common to all objects of a class.
 We can access instance variables through object references and Static Variables can be
accessed directly using the class name.
 The syntax for static and instance variables:
class Example
{
static int a; // static variable
int b; // instance variable
}
All variables use data type during declaration to restrict the type of data
to be stored. Therefore, we can say that 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. Every data type requires a
different amount of memory.

C++ supports a wide variety of data types and the programmer can select
the data type appropriate to the needs of the application. Data types
specify the size and types of values to be stored. However, storage
representation and machine instructions to manipulate each data type
differ from machine to machine, although C++ instructions are identical
on all machines.

C++ supports the following data types:

 Primary or Built-in or Fundamental data type


 Derived data types
 User-defined data types

Data types in C++ are mainly divided into three 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 - The integer data type is used to represent whole numbers


in a computer program. It is typically used to store values that do
not have a fractional component, such as the number of students in
a class or the number of items in an order.
In C++, the integer data type is represented by the keyword 'int'.

 Character - The character data type is used to represent individual


characters in a computer program. It is typically used to store
values that represent letters, digits, and other symbols.
In C++, the character data type is represented by the
keyword 'char'.

 Boolean - The Boolean data type is used to represent true/false


values in a computer program. It is typically used to store values
that can only be one of two options, such as yes/no, on/off, or
true/false.
In C++, the Boolean data type is represented by the keyword 'bool'.
 Floating Point - The floating point data type is used to represent
real numbers in a computer program. It is typically used to store
values that have a fractional component, such as 3.14 or 42.0.
In C++, the floating point data type is represented by the
keyword 'float'.

 Double Floating Point - Double floating point datatype, also


known as double in C++, is a data type used to store decimal
values with greater precision than a single floating point datatype. It
uses twice as many bits to store a value and can represent a larger
range of values than a single floating point.
In C++, the floating point data type is represented by the
keyword 'double'.

 Valueless or Void - The void data type in C++ is used to specify


that a function or a pointer does not return a value. It can also be
used as a placeholder for a data type when a function does not take
any arguments,

 Wide Character - A wide character, also known as wchar_t in C++,


is a data type used to represent a wide character, which is a
character that can take up more than one byte of storage. It is
commonly used to store characters from non-Latin scripts, such as
Chinese or Arabic, which require more than one byte to represent a
character.
2. Derived Data Type:The 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 - A function is a block of code that performs a specific


task and may or may not return a value. In C++, functions can be
defined using derived data types, which are data types that are
derived from or based on the built-in data types.
 Array - An array is a collection of variables of the same data type
stored in contiguous memory locations. Arrays in C++ are defined
using square brackets and can have one or more dimensions.
 Pointer - A pointer is a variable that stores the memory address of
another variable. Pointers in C++ are defined using the * operator
and are used to manipulate data stored in memory directly.
 Reference - A reference in C++ is a variable that acts as an alias
for another variable. It allows you to create a second name for a
variable, which can be used to modify the original variable's value.
3. Abstract or User-Defined Data Types: These 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 - A class in C++ is a user-defined data type that allows you to
create objects with their own data members and member functions.
It is a template for creating objects that define the attributes and
behaviors of those objects.
 Structure - A structure in C++ is a composite data type that allows
you to store multiple variables of different data types in a single
unit. Structures are defined using the struct keyword and can
contain variables, functions, and other data types.
 Union - A union in C++ is a derived data type that allows you to
store multiple variables of different data types in the same memory
location. Unlike a structure, which stores each variable in a separate
memory location, a union stores all variables in the same location
and allows only one variable to be accessed at a time.
 Enumeration - An enumeration in C++ is a user-defined data type
that consists of a set of named constants called enumerators. It
allows you to create a set of symbolic names for a set of integral
values, which can make your code more readable and maintainable.
Enumerations are defined using the enum keyword and can be
defined with or without a specified underlying type.

 Typedef defined Datatype - typedef is a keyword in C++ that


allows you to create a new name for an existing data type. It can be
used to give a data type a more descriptive or abbreviated name,
which can make your code more readable and maintainable.

No of Bytes taken up by char is 1


No of Bytes taken up by int is 4
No of Bytes taken up by float is 4
No of Bytes taken up by double is 8
No of Bytes taken up by long is 8
int a = 5;
long x = 9;
double p = 10.2;
float g = 2.5;
No of Bytes taken up by (a+g) is 4
No of Bytes taken up by (a+x) is 8
No of Bytes taken up by (a+p) is 8
No of Bytes taken up by (x+p) is 8

In programming , the scope of a variable is defined as the extent of the


program code within which the variable can be accessed or declared or
worked with. There are mainly two types of variable scopes:

Local Variables
Global Variables

Local Variables - Variables defined within a function or block are said to


be local to those functions.

Anything between ‘{‘ and ‘}’ is said to be inside a block.

Local variables do not exist outside the block in which they are declared,
i.e. they can not be accessed or used outside that block.

Declaring local variables: Local variables are declared inside a block

Global Variables - Global Variables can be accessed from any part of the
program.

They are available throughout the lifetime of a program.

They are declared at the top of the program outside all of the functions or
blocks.

Declaring global variables: Global variables are usually declared


outside of all of the functions and blocks, at the top of the program. They
can be accessed from any portion of the program.

NOTE - Whenever there is a local variable defined with same name as


that of a global variable then the compiler will give precedence to the
local variable

Data type modifiers available in C++ are:

 Signed
 Unsigned
 Short
 Long
Static keyword has different meanings when used with different types. We
can use static keyword with:

Static Variables : Variables in a function, Variables in a class


Static Members of Class : Class objects and Functions in a class

 Static variables in a Function: When a variable is declared as


static, space for it gets allocated for the lifetime of the
program. Even if the function is called multiple times, space for the
static variable is allocated only once and the value of variable in the
previous call gets carried through the next function call. This is
useful for implementing coroutines in C/C++ or any other
application where previous state of function needs to be stored.
 // C++ program to demonstrate
 // the use of static Static
 // variables in a Function
 #include <iostream>
 #include <string>
 using namespace std;

 void demo()
 {
 // static variable
 static int count = 0;
 cout << count << " ";

 // value is updated and
 // will be carried to next
 // function calls
 count++;
 }

 int main()
 {
 for (int i=0; i<5; i++)
 demo();
 return 0;
 }

Output
0 1 2 3 4
You can see in the above program that the variable count is declared as
static. So, its value is carried through the function calls. The variable
count is not getting initialized for every time the function is called.

 Static variables in a class: As the variables declared as static are


initialized only once as they are allocated space in separate static
storage so, the static variables in a class are shared by the
objects. There can not be multiple copies of same static variables
for different objects. Also because of this reason static variables can
not be initialized using constructors.

 Class objects as static: Just like variables, objects also when


declared as static have a scope till the lifetime of program.
Consider the below program where the object is non-static.
// CPP program to illustrate
// when not using static keyword
#include<iostream>
using namespace std;

class GfG
{
int i;
public:
GfG()
{
i = 0;
cout << "Inside Constructor\n";
}
~GfG()
{
cout << "Inside Destructor\n";
}
};

int main()
{
int x = 0;
if (x==0)
{
GfG obj;
}
cout << "End of main\n";
}
Output:
Inside Constructor
Inside Destructor
End of main
In the above program the object is declared inside the if block as non-static. So,
the scope of variable is inside the if block only. So when the object is created the
constructor is invoked and soon as the control of if block gets over the destructor
is invoked as the scope of object is inside the if block only where it is declared.
Let us now see the change in output if we declare the object as static.

 Static functions in a class: Just like the static data members or


static variables inside the class, static member functions also does
not depend on object of class. We are allowed to invoke a static
member function using the object and the ‘.’ operator but it is
recommended to invoke the static members using the class name
and the scope resolution operator.
Static member functions are allowed to access only the
static data members or other static member functions, they
can not access the non-static data members or member functions of
the class.
// CPP program to illustrate
// class objects as static
#include<iostream>
using namespace std;

class GfG
{
int i = 0;

public:
GfG()
{
i = 0;
cout << "Inside Constructor\n";
}

~GfG()
{
cout << "Inside Destructor\n";
}
};

int main()
{
int x = 0;
if (x==0)
{
static GfG obj;
}
cout << "End of main\n";
}
Output
Inside Constructor
End of main
Inside Destructor
You can clearly see the change in output. Now the destructor is invoked after the
end of main. This happened because the scope of static object is through out the
life time of program.
Whenever const keyword is attached to any method(), variable, pointer variable,
and with the object of a class it prevents that specific object/method()/variable
from modifying its data items value.

There are a certain set of rules for the declaration and initialization of the
constant variables -:

 The const variable cannot be left un-initialized at the time of the


assignment.
 It cannot be assigned value anywhere in the program.
 Explicit value needed to be provided to the constant variable at the
time of declaration of the constant variable.

The auto keyword specifies that the type of the variable that is being
declared will be automatically deducted from its initializer. In the case of
functions, if their return type is auto then that will be evaluated by return
type expression at runtime.

Note: The variable declared with auto keyword should be initialized at the
time of its declaration only or else there will be a compile-time error.

Typeid is an operator which is used where the dynamic type of an object


needs to be known.

typeid(x).name() returns the data type of x, for example, it return ‘i’ for
integers, ‘d’ for doubles, ‘Pi’ for the pointer to integer etc. But the actual
name returned is mostly compiler dependent.

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.
In C++ programming language, we use literals to represent fixed values.
C++ supports various types of literals including integer literals, floating-
point literals, character literals, and string literals.
Literals are fundamental elements used to represent constant values used
in C++ programming language. These constants can include numbers,
characters, strings, and more. Understanding and using the literals is
essential in C++ for data assignment, calculations, and data
representation. They are generally present as the right operand in the
assignment operation.

There are five types of literals in C++ which are:


1. Integer Literals
2. Floating Point Literals
3. Character Literals
4. String Literals
5. Boolean Literals

A type cast is basically a conversion from one type to another. There are
two types of type conversion:

1. Implicit Type Conversion Also known as ‘automatic type


conversion’.
o Done by the compiler on its own, without any external trigger
from the user.
o Generally takes place when in an expression more than one
data type is present. In such condition type conversion (type
promotion) takes place to avoid lose of data.
o All the data types of the variables are upgraded to the data
type of the variable with largest data type.
bool -> char -> short int -> int ->

unsigned int -> long -> unsigned ->

long long -> float -> double -> long double

2.Explicit Type Conversion: This process is also called type casting


and it is user-defined. Here the user can typecast the result to make it of a
particular data type.

In C++, it can be done by two ways:

Conversion using Cast operator: A Cast operator is an unary


operator which forces one data type to be converted into another data
type.

#include <iostream>
using namespace std;
int main()
{
float f = 3.5;

// using cast operator


int b = static_cast<int>(f);

cout << b;
}

C++ comes with libraries that provide us with many ways for performing
input and output. In C++ input and output are performed in the form of a
sequence of bytes or more commonly known as streams.

 Input Stream: If the direction of flow of bytes is from the device(for


example, Keyboard) to the main memory then this process is called
input.
 Output Stream: If the direction of flow of bytes is opposite, i.e.
from main memory to device( display screen ) then this process is
called output.

Header files available in C++ for Input/Output operations are:

1. iostream: iostream stands for standard input-output stream. This


header file contains definitions of objects like cin, cout, cerr, etc.
2. iomanip: iomanip stands for input-output manipulators. The
methods declared in these files are used for manipulating streams.
This file contains definitions of setw, setprecision, etc.
3. fstream: This header file mainly describes the file stream. This
header file is used to handle the data being read from a file as input
or data being written into the file as output.
The two instances cout in C++ and cin in C++ of iostream class are
used very often for printing outputs and taking inputs respectively. These
two are the most basic methods of taking input and printing output in C+
+. To use cin and cout in C++ one must include the header
file iostream in the program.

 Standard output stream (cout): Usually the standard output


device is the display screen. The C++ cout statement is the
instance of the ostream class. It is used to produce output on the
standard output device which is usually the display screen. The data
needed to be displayed on the screen is inserted in the standard
output stream (cout) using the insertion operator(<<).
 standard input stream (cin): Usually the input device in a
computer is the keyboard. C++ cin statement is the instance of the
class istream and is used to read input from the standard input
device which is usually a keyboard.
The extraction operator(>>) is used along with the object cin for
reading inputs. The extraction operator extracts the data from the
object cin which is entered using the keyboard.

 Un-buffered standard error stream (cerr): The C++ cerr is the


standard error stream that is used to output the errors. This is also
an instance of the iostream class. As cerr in C++ is un-buffered so it
is used when one needs to display the error message immediately.
It does not have any buffer to store the error message and display it
later.
 The main difference between cerr and cout comes when you would
like to redirect output using “cout” that gets redirected to file if you
use “cerr” the error doesn’t get stored in file.(This is what un-
buffered means ..It cant store the message)

 buffered standard error stream (clog): This is also an instance


of ostream class and used to display errors but unlike cerr the error
is first inserted into a buffer and is stored in the buffer until it is not
fully filled. or the buffer is not explicitly flushed (using flush()). The
error message will be displayed on the screen too.

The cin object C++ is used to accept the input from the standard input
device i.e., keyboard. it is the instance of the class istream. It is
associated with the standard C input stream stdin. The extraction
operator(>>) is used along with the object cin for reading inputs. The
extraction operator extracts the data from the object cin which is entered
using the keyboard.

standard input stream (cin): Usually the input device in a computer is


the keyboard. C++ cin statement is the instance of the class istream and
is used to read input from the standard input device which is usually a
keyboard.
The extraction operator(>>) is used along with the object cin for reading
inputs. The extraction operator extracts the data from the
object cin which is entered using the keyboard.

The escape sequences are special non-printing characters that are used
to control the printing behavior of the output stream objects (such as
‘cout’). These characters are not displayed in the output. An escape
sequence is prefixed with a backslash (\) and a coded character is used to
control the printing behavior. The backslash (\) is called an escape
character. So the escape sequence looks like two characters.
The escape sequence is used inside a string constant or independently.
These are written in single or double-quotes. The escape sequence can be
inserted in any position of the string such as:

 At the beginning of the string.


 In the middle of the string.
 At the end of the string etc.
For example, the escape sequence ‘\n’ is used to insert a new line. The
cursor moves from the current position on the output device to the
beginning of the next line. If escape sequence ‘\n’ is inserted at the
beginning of the string then the string will be printed after printing a blank
line e.g.

cout<<”\nWelcome”;
Note - The line continuation sequence (\ followed by a new-line character)
is not an escape sequence. It is used in character strings to indicate that
the current line of source code continues on the next line.

 The value of an escape sequence represents the member of the


character set used at run time. Escape sequences are translated
during preprocessing. For example, on a system using the ASCII
character codes, the value of the escape sequence \x56 is the letter
V.
 Use escape sequences only in character constants or in string
literals. An error message is issued if an escape sequence is not
recognized.
 In string and character sequences, when you want the backslash to
represent itself (rather than the beginning of an escape sequence),
you must use a \ backslash escape sequence. For example: cout
<< "The escape sequence \\n." << endl;
Manipulators are helping functions that can modify the input/output
stream. It does not mean that we change the value of a variable, it only
modifies the I/O stream using insertion (<<) and extraction (>>)
operators.

Manipulators are special functions that can be included in the I/O


statement to alter the format parameters of a stream.

Manipulators are operators that are used to format the data display.

To access manipulators, the file iomanip.h should be included in the


program.

Some important manipulators in <ios> are:

 showpos: It forces to show a positive sign on positive numbers.


 noshowpos: It forces not to write a positive sign on positive
numbers.
 showbase: It indicates the numeric base of numeric values.
 // Code example demonstrating the use of showbase and noshowbase

 #include <iostream>
 #include <iomanip>

 using namespace std;

 int main() {
 cout << showbase << hex << 123 << endl; // Outputs: 0x7b
 cout << showbase << oct << 456 << endl; // Outputs: 0o710
 cout << showbase << dec << 789 << endl; // Outputs: 789
 cout << noshowbase << hex << 345 << endl; // Outputs: 159
 }
 uppercase: It forces uppercase letters for numeric values.
 nouppercase: It forces lowercase letters for numeric values.
 fixed: It uses decimal notation for floating-point values.
 scientific: It uses scientific floating-point notation.
 hex: Read and write hexadecimal values for integers and it works
same as the setbase(16).
 dec: Read and write decimal values for integers i.e. setbase(10).
 oct: Read and write octal values for integers i.e. setbase(10).
 // Code implementation showing the use of hex, dec and oct

 #include <iostream>
 #include <iomanip>

 using namespace std;

 int main() {
 cout << hex << 123 << endl; // Outputs: 7b
 cout << oct << 456 << endl; // Outputs: 710
 cout << dec << 789 << endl; // Outputs: 789
 }

 left: It adjusts output to the left.


 right: It adjusts output to the right.
 setfill: The setfill manipulator is used in C++ to set the fill
character that is used to pad a field when outputting a value using
the setw manipulator. The setfill manipulator is typically used in
conjunction with the setw manipulator, which sets the field width for
output.
 setw: In C++, the setw manipulator is used to set the width of the
output field for certain types of data. When outputting data to the
console or to a file, you can use setw to specify the minimum
number of characters that should be used to represent the output
data. This can be useful for formatting the output and aligning
columns of data.

// Code implementation showing the use of left, right, setfill, setw

#include <iostream>
#include <iomanip>

using namespace std;

int main() {
cout << left << setw(10) << setfill('-') << "Apple" << endl; //
Output: Apple-----
cout << right << setw(10) << setfill('-') << "Orange" << endl; //
Output: ----Orange
}
The left manipulator causes the output to be left-aligned within the
specified width. The right manipulator causes the output to be right-
aligned within the specified width.

The setw manipulator sets the width of the output field, and
the setfill manipulator sets the character that should be used to fill any
unused space in the output field.

Floating Point Default Print Format

Default Printing Format


 No trailing zeros
 Precision means total digits(excluding the digits used after e).
 Default Precision value is 6.
 When value before decimal point does not fit in 6 digits, power format is used. For
example - 1234568.3 is printed as 1.23457e+06.
 #include<iostream>
 using namespace std;
 int main()
 {
 double x = 1.2300;
 cout << x << '\n';
 double y = 1567.56732;
 cout << y << '\n';
 double z = 1244567.45;
 cout << z << '\n';
 double w = 124456.67;
 cout << w << '\n';
 double u = 123e+2;
 cout << u << '\n';
 return 0;
 }
 Output
 1.23
 1567.57
 1.24457e+06
 124457
 12300
 Floating point Manipulating Default Format

 Manipulating Default Format


 setprecision(n) - Changes the default precision.
 showpoint() - shows trailing zeros, noshowpoint() reverts it.
 showpos() - Show + sign for positive values. no showpos() reverts it.
 uppercase() - prints 'e' as 'E'. nouppercase() reverts it.
 #include<iostream>
 #include<iomanip>
 using namespace std;
 int main()
 {
 cout << setprecision(4);
 double x = 15.5683, y = 34267.1;
 cout << x << ' ' << y << ' ' << '\n';
 double z = 1.23;
 cout << showpoint << z << '\n';
 cout << showpos << z << '\n';
 cout << uppercase << y << '\n';
 return 0;
 }
 Output
 15.57 3.427e+04
 1.230
 +1.230
 +3.427E+04

Floating Point Fixed and Scientific

Fixed and Scientific

In Fixed floating point no power (or e) uses. Ex - 10.5, 122.5.

In Scientific floating point we will use e. Ex - 1.2e + 04, 1.45e +06. std::scientific

 In both precision means digits after the decimal point.


 If there are not enough digits then the trailing zeros are shown in both.
 We can set back to default using "default float."
 #include<iostream>
 #include<iomanip>
 using namespace std;
 int main()
 {
 double x = 1.23, y = 1122456.453;
 cout << std::fixed;
 cout << x << "\n"
 << y << "\n";
 cout << std::setprecision(2);
 cout << x << "\n"
 << y << "\n";
 double z = 1.2e+7;
 cout << z;
 return 0;
 }
 1.230000
 1122456.453000
 1.23
 1122456.45
 12000000.00

ofstream in C++ stands for "output file stream" and is part of the <fstream> library. It is
used to create files and write data to them.
Operators in C++ are special symbols that perform specific operations on one, two, or three
operands, and return a result. They form the foundation of any programming
language. In C++, we have built-in operators to provide the required
functionality.

An operator operates the operands. For example,

int c = a + b;
Here, ‘+’ is the addition operator. ‘a’ and ‘b’ are the operands that are
being ‘added’.

Operators in C++ can be classified into 6 types:

1. Arithmetic Operators
2. Relational Operators
3. Logical Operators
4. Bitwise Operators
5. Assignment Operators
6. Ternary or Conditional Operators
In C++, the division operator (/) is used to divide one operand by another. The result of the division
operation depends on the types of the operands involved (integers or floating-point numbers).

When one or both operands are floating-point numbers (e.g., float, double), the division operator
performs floating-point division, which retains the fractional part of the result.

Assignment operators are used to assigning value to a variable. The left side
operand of the assignment operator is a variable and right side operand of the
assignment operator is a value. The value on the right side must be of the same
data-type of the variable on the left side otherwise the compiler will raise an
error.

// C++ program to demonstrate


// working of Assignment operators

#include <iostream>
using namespace std;

int main()
{

// Assigning value 10 to a
// using "=" operator
int a = 10;
cout << "Value of a is "<<a<<"\n";
// Assigning value by adding 10 to a
// using "+=" operator
a += 10;
cout << "Value of a is "<<a<<"\n";

// Assigning value by subtracting 10 from a


// using "-=" operator
a -= 10;
cout << "Value of a is "<<a<<"\n";

// Assigning value by multiplying 10 to a


// using "*=" operator
a *= 10;
cout << "Value of a is "<<a<<"\n";

// Assigning value by dividing 10 from a


// using "/=" operator
a /= 10;
cout << "Value of a is "<<a<<"\n";

return 0;
}
Value of a is 10
Value of a is 20
Value of a is 10
Value of a is 100
Value of a is 10

Relational operator: relational operators are operators used for


comparing two elements, these are mostly used with if-else conditions as they
return true-false as result.
#include<iostream>
using namespace std;
int main()
{
int x = 10, y = 20 ;
cout << (x<y) << "\n"
<< (x>y) << "\n"
<< (x==y) << "\n"
<< (x>=y) << "\n"
<< (x<=y) << "\n"
<< (x!=y) << "\n";
return 0;
}

Logical Operators
These operators are used to combine two or more conditions or
constraints or to complement the evaluation of the original condition in
consideration. The result returns a Boolean value, i.e., true or false.

Short-Circuiting in Logical Operators:

 In the case of logical AND, the second operand is not evaluated if


the first operand is false. For example, program 1 below doesn’t
print “GeeksQuiz” as the first operand of logical AND itself is false.
 #include <iostream>
 using namespace std;

 int main()
 {
 int a = 10, b = 4;
 bool res = ((a == b) && cout << "GeeksQuiz");
 return 0;
 }

#include <iostream>
using namespace std;

int main()
{
int a = 10, b = 4;
bool res = ((a != b) && cout << "GeeksQuiz");
return 0;
}
Output
GeeksQuiz

Boolean Evaluation of std::ostream:

 When an std::ostream object is used in a boolean context, it is converted to true if


the stream is in a good state (i.e., no errors have occurred on the stream).
 This is because std::ostream has an overloaded operator void* or a similar
mechanism that allows it to be evaluated in a boolean context, which checks if the
stream state is good.

In the case of logical OR, the second operand is not evaluated if the first
operand is true. For example, program 1 below doesn’t print “GeeksQuiz” as the
first operand of logical OR itself is true

There is also a three-way comparison operator in C++ called <=>,


which is sometimes called the "spaceship operator." This operator
compares two values and returns:

 0 if the values are equal


 1 if the first value is greater than the second value
 -1 if the first value is less than the second value
 int result = a <=> b;
 if (result == 0) {
 // a and b are equal
 } else if (result == 1) {
 // a is greater than b
 } else if (result == -1) {
 // a is less than b
 }

int a = 10, b = 4; auto result = a <=> b; cout << result; is there something wrong in this piece
of code
Yes, there is an issue with the code. The main problem is that the result of the spaceship operator
(<=>) is not directly printable using std::cout. The operator<=> returns a
std::strong_ordering object (or similar), which does not have a direct textual representation
that can be printed with std::cout.

Operator Precedence determines which operation is performed first in an


expression with more than one operators with different precedence.

Operators Associativity is used when two operators of same precedence


appear in an expression. Associativity can be either Left to Right
or Right to Left.
For example: ‘*’ and ‘/’ have same precedence and their associativity
is Left to Right, so the expression “100 / 10 * 10” is treated as “(100 / 10) * 10”.
Bitwise Operators

These operators are used to perform bit-level operations on the operands.


The operators are first converted to bit-level and then the calculation is
performed on the operands. The mathematical operations such as
addition, subtraction, multiplication, etc. can be performed at the bit-level
for faster processing.
The line #include <bits/stdc++.h> is commonly used in competitive programming. It includes
almost all standard C++ libraries in one go. This can save time during contests but isn't
recommended for production code because it can significantly increase compilation time and lead to
bloated binaries.

Overflow occurs when a calculation produces a result that is outside the range that can be
represented with a given number of bits. In the context of integer arithmetic in programming,
overflow happens when an operation results in a value that is too large (positive overflow) or too
small (negative overflow) to be stored in the integer type.
// Efficient CPP program to find sum of first
// n natural numbers that avoids overflow if
// result is going to be within limits.
#include<iostream>
using namespace std;

// Returns sum of first n natural


// numbers
int findSum(int n)
{
if (n % 2 == 0)

// Here multiplying by 1LL help to


// perform calculations in long long,
// so that answer should not be overflowed
return (n / 2) * 1LL * (n + 1);

// If n is odd, (n+1) must be even


else

// Here multiplying by 1LL help to


// perform calculations in long long,
// so that answer should not be overflowed
return ((n + 1) / 2) * 1LL * n;
}

// Driver code
int main()
{
int n = 5;
cout << findSum(n);
return 0;
}

Scope resolution operator has highest precedence in c++


Modulus operator and division operator have same operator

In summary, the operators in C++ with right-to-left associativity include:

 Unary operators (excluding postfix)


 Type casts
 The ternary conditional operator
 Assignment operators

 Integer Division: Both operands are integers; the result is an integer with the fractional
part discarded.

 Example: 10 / 3 results in 3.
 Floating-Point Division: At least one operand is a floating-point number; the result is a
floating-point number with the fractional part retained.

 Example: 10.0 / 3.0 results in 3.33333.

 Mixed-Type Division: An integer and a floating-point number; the integer is promoted to


a floating-point number, and the division is performed as floating-point division.

 Example: 10 / 3.0 results in 3.33333.

Performing division (/) on floating-point numbers in C++ always results in a floating-point number,
regardless of the values involved. The precision of the result depends on the data type ( float or
double) used for the operands. This contrasts with integer division ( /) where the result is truncated
towards zero and is an integer.

cout is an instance of std::ostream, which is a part of the C++ Standard Library and is
used for outputting data to the standard output, typically the console. Its name stands for
"console output."

The role of cout, along with the stream insertion operator (<<), is to facilitate the easy and
formatted output of data. Here's a detailed explanation:

Role of cout

1. Standard Output Stream: cout is connected to the standard output stream (usually
the console or terminal). It is used to display information to the user.
2. Formatted Output: cout allows for formatted output, meaning you can output
various data types (integers, floating-point numbers, strings, etc.) in a readable format.
3. Chaining: cout supports chaining of multiple insertions in a single statement,
enabling the output of multiple pieces of data in one line of code.

Stream Insertion Operator (<<)

The stream insertion operator (<<) is used to insert data into the output stream. Here's what it
does:

1. Insertion: It inserts the data on its right side into the stream on its left side.
2. Overloadable: The operator can be overloaded for user-defined types, allowing
custom objects to be output using cout.
3. Returns the Stream: It returns the stream after inserting the data, which allows
chaining of multiple << operations.
#include <iostream>
using namespace std;

int main()
{
int i = 20;

// Check if i is 10
if (i == 10)
cout << "i is 10";

// Since is not 10
// Then execute the else statement
else
cout << "i is 20\n";

cout << "Outside if-else block";

return 0;
}

#include <iostream>
using namespace std;

int main()
{
int i = 20;

if (i == 10)
cout << "i is 10";
else if (i == 15)
cout << "i is 15";
else if (i == 20)
cout << "i is 20";
else
cout << "i is not present";
}

Switch case statement evaluates a given expression and based on the


evaluated value(matching a certain condition), it executes the statements
associated with it. Basically, it is used to perform different actions based
on different conditions(cases).

 Switch case statements follow a selection-control mechanism and


allow a value to change control of execution.
 They are a substitute for long if statements that compare a variable
to several integral values.
 The switch statement is a multiway branch statement. It provides an
easy way to dispatch execution to different parts of code based on
the value of the expression.
In C++, the switch statement is used for executing one condition from
multiple conditions. It is similar to an if-else-if ladder.

Switch statement consists of conditional based cases and a default case.

In a switch statement, the “case value” can be of “char” and “int” type.
Following are some of the rules while using the switch statement:
1. There can be one or N numbers of cases.
2. The values in the case must be unique.
3. Each statement of the case can have a break statement. It is optional.

Used for multi way branching


#include <iostream>
#include <string>

// Tools
const int Pen{ 10 };
const int Marker{ 20 };
const int Eraser{ 30 };
const int Rectangle{ 40 };
const int Circle{ 50 };
const int Ellipse{ 60 };

int main(){

int tool {Eraser};

switch (tool)
{
case Pen : {
std::cout << "Active tool is Pen" << std::endl;
}
break;

case Marker : {
std::cout << "Active tool is Marker" << std::endl;
}
break;

case Eraser :
case Rectangle :
case Circle : {
std::cout << "Drawing Shapes" << std::endl;
}
break;

case Ellipse : {
std::cout << "Active tool is Ellipse" << std::endl;
}
break;

default: {
std::cout << "No match found" << std::endl;
}
break;
}

std::cout << "Moving on" << std::endl;

/*
// Condition can only be integer of enum (We'll learn about enums
later in the course)
std::string name {"John"};
switch (name) // Compiler error!
{

}
*/

return 0;
}

Here's a summary of logical operators in C++:

 && or and: Logical AND.


 || or or: Logical OR.
 ! or not: Logical NOT.
A function is a set of statements that take inputs, do some specific
computation, and produce output. The idea is to put some commonly or
repeatedly done tasks together and make a function so that instead of writing
the same code again and again for different inputs, we can call the function.
In simple terms, a function is a block of code that only runs when it is called.

Why Do We Need Functions?


 Functions help us in reducing code redundancy. If functionality is
performed at multiple places in software, then rather than writing the
same code, again and again, we create a function and call it everywhere.
This also helps in maintenance as we have to change at one place if we
make future changes to the functionality.
 Functions make code modular. Consider a big file having many lines of
code. It becomes really simple to read and use the code if the code is
divided into functions.
 Functions provide abstraction. For example, we can use library functions
without worrying about their internal work.

Let us first understand in brief what a stack data structure is:

A stack is a way of storing data in a specific order. Imagine a stack of


plates. You can only add a new plate to the top of the stack, or take the
top plate off the stack. This means that the most recently added plate is
the first one to be removed (also known as last in, first out).

In C++, a stack is implemented as a template class, which means that it


can store data of any type (for example, integers, strings, or custom
classes). You can create a stack and add elements to it using the "push"
function, and remove elements from it using the "pop" function. The "top"
function can be used to see the element at the top of the stack without
removing it.
Please note that, this is just to explain you the concept of
stack data structure.
We would be dealing with stack data structure in details later
on in the course.
The function call stack is a data structure that is used to store information
about the active functions in a program. When a function is called, its
information is pushed onto the top of the stack, and when the function
returns, its information is popped off from the top of the stack.

The function call stack is important because it allows the program to keep
track of which function is currently being executed and which functions
have been called. It also enables the program to return to the correct
location when a function finishes its execution.

#include <iostream>
using namespace std;

void printMessage() {
cout << "Hello, world!" << endl;
}

int add(int x, int y) {


return x + y;
}

int main() {
int a = 3;
int b = 4;
int c = add(a, b); // c will be assigned the value 7
printMessage();
return 0;
}
Output
Hello, world!
When this program is executed, the following sequence of events occurs:

1. The main() function is called and its information is pushed onto the
top of the function call stack.
2. The add() function is called and its information is pushed onto the
top of the stack.
3. The add() function executes and returns a result, which is then
assigned to the variable c.
4. The add() function's information is popped off the top of the stack.
5. The printMessage() function is called and its information is pushed
onto the top of the stack.
6. The printMessage() function executes and prints a message to the
screen.
7. The printMessage() function's information is popped off the top of
the stack.
8. The main() function returns and its information is popped off the
top of the stack.
In this example, the function call stack is used to store information about
the main(), add(), and printMessage() functions as they are executed.
When a function is called, its information is pushed onto the top of the
stack, and when the function returns, its information is popped of fromf
the top of the stack. This allows the program to keep track of which
function is currently being executed and to return to the correct location
when a function finishes its execution.

The function call stack is managed by the compiler and is not visible to
the programmer. However, it is an important part of how functions works
in C++ and plays a crucial role in the execution of a program.

Function Declaration
A function declaration tells the compiler about the number of parameters
function takes data-types of parameters, and returns the type of function.
Putting parameter names in the function declaration is optional in the
function declaration, but it is necessary to put them in the definition.
Below are an example of function declarations. (parameter names are not
there in the below declarations)
User Defined Function

User Defined functions are user/customer-defined blocks of code specially


customized to reduce the complexity of big programs. They are also
commonly known as “tailor-made functions” which are built only to
satisfy the condition in which the user is facing issues meanwhile reducing
the complexity of the whole program.

Library Function

Library functions are also called “builtin Functions“. These functions are
a part of a compiler package that is already defined and consists of a
special function with special and different meanings. Builtin Function gives
us an edge as we can directly use them without defining them whereas in
the user-defined function we have to declare and define a function before
using them.
For Example: sqrt(), setw(), strcat(), etc.

what is difference between parameter and arguments in function in c++

In C++, the terms "parameters" and "arguments" are related but distinct concepts in the
context of functions. Here’s a breakdown of the differences:

Parameters:
 Definition: Parameters are variables listed in the function's definition.
 Purpose: They act as placeholders for the values that will be passed to the function.
 Scope: They are local to the function and exist only within the function's body.

void printSum(int a, int b) { // a and b are parameters

std::cout << (a + b) << std::endl;

Arguments:

 Definition: Arguments are the actual values or expressions passed to the function
when it is called.
 Purpose: They provide the data that the function will operate on.
 Scope: They exist in the context where the function is called.

int main() {

printSum(5, 10); // 5 and 10 are arguments

return 0;

Key Differences:

1. Location in Code:
o Parameters appear in the function declaration and definition.
o Arguments appear in the function call.
2. Role:
o Parameters specify what kind of data the function expects.
o Arguments provide the actual data that is passed to the function.
3. Binding:
o When a function is called, arguments are passed to the function and assigned
to the corresponding parameters.

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.
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 must also have a default value.
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).

Inline functions::
When the program executes the function call instruction the CPU stores
the memory address of the instruction following the function call, copies
the arguments of the function on the stack and finally transfers control to
the specified function. The CPU then executes the function code, stores
the function return value in a predefined memory location/register and
returns control to the calling function. This can become overhead if the
execution time of function is less than the switching time from the caller
function to called function (callee). For functions that are large and/or
perform complex tasks, the overhead of the function call is usually
insignificant compared to the amount of time the function takes to run.
However, for small, commonly-used functions, the time needed to make
the function call is often a lot more than the time needed to actually
execute the function’s code. This overhead occurs for small functions
because execution time of small function is less than the switching time.

Basically, in case of normal functions, the program control


jumps to the place where it is
defined. But in case of inline functions, it can be understood
that the entire function
definition is brought to the place where it is called.
C++ provides an inline functions to reduce the function call overhead.
Inline function is a function that is expanded in line when it is called.
When the inline function is called whole code of the inline function gets
inserted or substituted at the point of inline function call. This substitution
is performed by the C++ compiler at compile time. Inline function may
increase efficiency if it is small.
The syntax for defining the function inline is:

inline return-type function-name(parameters)


{
// function code
}

MACROS::
In C++, a macro is a preprocessor directive that defines a piece of code which can be reused
throughout the program. Macros are handled by the preprocessor, which processes the source code
before it is compiled by the compiler. They provide a way to define constants, functions, or code
snippets that can be inserted into the program wherever needed.

Types of Macros:

1. Object-like Macros:
o These are similar to constants and are used to define constant values or
expressions.
o Syntax: #define MACRO_NAME value
o Example:

cpp
Copy code
#define PI 3.14159
#include <iostream>

int main() {
std::cout << "Value of PI: " << PI << std::endl;
return 0;
}

2. Function-like Macros:
o These macros resemble functions and can take arguments. However, they are
not type-checked like functions.
o Syntax: #define MACRO_NAME(arguments) code
o Example:

cpp
Copy code
#define SQUARE(x) ((x) * (x))
#include <iostream>

int main() {
std::cout << "Square of 5: " << SQUARE(5) << std::endl;
return 0;
}

Preprocessor Directives:

 #define: Used to define a macro.


 #undef: Used to undefine a macro.
 #ifdef, #ifndef, #if, #else, #elif, #endif: Used for conditional compilation
based on whether a macro is defined or evaluates to true.

Advantages of Macros:

1. Code Reusability: Macros can reduce code duplication by defining commonly used
code snippets or values.
2. Readability: They can improve code readability by using meaningful names instead
of hard-coded values or complex expressions.

Disadvantages of Macros:

1. No Type Checking: Macros are not type-checked, which can lead to errors that are
difficult to debug.
2. Debugging Difficulties: Since macros are expanded by the preprocessor, it can be
challenging to trace errors in the expanded code.
3. Code Bloat: Overuse of macros, especially function-like macros, can lead to code
bloat as the macro code is inserted each time it is used.

Example Illustrating Macro Pitfalls:


cpp
Copy code
#define SQUARE(x) ((x) * (x))

int main() {
int result = SQUARE(5 + 2); // This will expand to ((5 + 2) * (5 + 2))
which is incorrect
std::cout << "Result: " << result << std::endl; // Outputs 49 instead
of 49
return 0;
}

Best Practices:
 Use macros for simple constants.
 Prefer inline functions or const variables for more complex operations or values to
benefit from type safety and better debugging support.

Yes, the use of the macro INCREMENT_AND_SQUARE with an argument like y++ can lead to
unexpected behavior because the argument is evaluated multiple times. This can cause side
effects such as incrementing y more than once, which is often not the intended behavior.
Here's a detailed explanation:

Problem with Multiple Evaluations:

When you use the macro INCREMENT_AND_SQUARE(y++), the macro expands as follows:

cpp
Copy code
#define INCREMENT_AND_SQUARE(x) ((x + 1) * (x + 1))

// Expansion
std::cout << ((y++ + 1) * (y++ + 1));

In this case, y++ is incremented twice:

1. First y++ increments y from 3 to 4 but returns 3.


2. Second y++ increments y from 4 to 5 but returns 4.

This results in the expression ((3 + 1) * (4 + 1)), which evaluates to 4 * 5 = 20.

Function overloading is a feature of object-oriented programming where


two or more functions can have the same name but different parameters.
When a function name is overloaded with different jobs it is called
Function Overloading. In Function Overloading “Function” name should be
the same and the arguments should be different.

The parameters should follow any one or more than one of the following
conditions for Function overloading:

 Parameters should have a different type


add(int a, int b)
add(double a, double b)

Loops:
Using Loops
In Loop, the statement needs to be written only once and the loop will be
executed 10 times as shown below. In computer programming, a loop is a
sequence of instructions that is repeated until a certain condition is
reached.

 An operation is done, such as getting an item of data and changing


it, and then some condition is checked such as whether a counter
has reached a prescribed number.
 Counter not Reached: If the counter has not reached the desired
number, the next instruction in the sequence returns to the first
instruction in the sequence and repeats it.
 Counter reached: If the condition has been reached, the next
instruction “falls through” to the next sequential instruction or
branches outside the loop.
There are mainly two types of loops:
1. Entry Controlled loops: In this type of loop, the test condition is
tested before entering the loop body. For Loop and While Loop is
entry-controlled loops.
2. Exit Controlled Loops: In this type of loop the test condition is
tested or evaluated at the end of the loop body. Therefore, the loop
body will execute at least once, irrespective of whether the test
condition is true or false. the do-while loop is exit controlled loop.
S.N
Loop Type and Description
o.

while loop – First checks the condition, then executes the


1.
body.

for loop – firstly initializes, then, condition check, execute


2.
body, update.

do-while loop – firstly, execute the body then condition


3.
check

While studying for loop we have seen that the number of iterations
is known beforehand, i.e. the number of times the loop body is needed
to be executed is known to us. while loops are used in situations
where we do not know the exact number of iterations of the
loop beforehand. The loop execution is terminated on the basis of the
test conditions.
We have already stated that a loop mainly consists of three statements –
initialization expression, test expression, and update expression. The
syntax of the three loops – For, while, and do while mainly differs in the
placement of these three statements.

Syntax:

initialization expression;
while (test_expression)
{
// statements

update_expression;
}
A for loop is a repetition control structure that allows us to write a loop
that is executed a specific number of times. The loop enables us to
perform n number of steps together in one line.

Syntax:

for (initialization expr; test expr; update expr)


{
// body of the loop
// statements we want to execute
}
Example1:

for(int i = 0; i < n; i++)


{
// BODY
}
Example2:

for(auto element:arr)
{
//BODY
}
In for loop, a loop variable is used to control the loop. First, initialize this
loop variable to some value, then check whether this variable is less than
or greater than the counter value. If the statement is true, then the loop
body is executed and the loop variable gets updated. Steps are repeated
till the exit condition comes.

 Initialization Expression: In this expression, we have to initialize


the loop counter to some value. for example: int i=1;
 Test Expression: In this expression, we have to test the condition.
If the condition evaluates to true then we will execute the body of
the loop and go to update expression otherwise we will exit from the
for a loop. For example: i <= 10;
 Update Expression: After executing the loop body this expression
increments/decrements the loop variable by some value. for
example: i++;

Loops come into use when we need to repeatedly execute a block of


statements. Like while the do-while loop execution is also terminated
on the basis of a test condition. The main difference between a do-while
loop and a while loop is in the do-while loop the condition is tested at the
end of the loop body, i.e do-while loop is exit controlled whereas the other
two loops are entry-controlled loops.
Note: In the do-while loop, the loop body will execute at least once
irrespective of the test condition.
do
{
// loop body

update_expression;
}
while (test_expression);
Note: Notice the semi – colon(“;”) in the end of loop.
The various parts of the do-while loop are:

1. Test Expression: In this expression, we have to test the condition.


If the condition evaluates to true then we will execute the body of
the loop and go to the update expression. Otherwise, we will exit
from the while loop.
2. Update Expression: After executing the loop body, this expression
increments/decrements the loop variable by some value.
3. Body: It is the Collection of statements i.e, variables and functions,
etc. The condition is not satisfied until the condition is executed
automatically after a successful iteration. do-while loop, code can be
used to print simple names, execute complex algorithms, or perform
functional operations.

The break in C++ is a loop control statement which is used to terminate


the loop. As soon as the break statement is encountered from within a
loop, the loop iterations stops there and control returns from the loop
immediately to the first statement after the loop.
Syntax:

break;
Basically break statements are used in the situations when we are not
sure about the actual number of iterations for the loop or we want to
terminate the loop based on some condition.

Continue is also a loop control statement just like the break


statement. continue statement is opposite to that of break statement,
instead of terminating the loop, it forces to execute the next iteration of
the loop.
As the name suggest the continue statement forces the loop to continue
or execute the next iteration. When the continue statement is executed in
the loop, the code inside the loop following the continue statement will be
skipped and next iteration of the loop will begin.
Syntax:

continue;

Array

1. It is a group of variables of similar data types referred to by a single


element.
2. Its elements are stored in a contiguous memory location.
3. The size of the array should be mentioned while declaring it.
4. Array elements are always counted from zero (0) onward.
5. Array elements can be accessed using the position of the element in
the array.
6. The array can have one or more dimensions.
An array in C++ a collection of similar data items stored at contiguous
memory locations and elements can be accessed randomly using indices
of an array. They can be used to store the collection of primitive data
types such as int, float, double, char, etc of any particular type. To add to
it, an array in C++ can store derived data types such as structures,
pointers etc. Given below is the picture representation of an array.
// C++ program to traverse
// the array
#include <bits/stdc++.h>
using namespace std;

// Function to traverse and


// print the array
void printArray(int* arr, int n)
{
int i;

cout << "Array: ";


for (i = 0; i < n; i++)
{
cout << arr[i] << " ";
}
}

// Driver code
int main()
{
int arr[] = {2, -1, 5, 6, 0, -3};
int n = sizeof(arr) / sizeof(arr[0]);

printArray(arr, n);
return 0;
}
// C++ program to traverse the
// array using range-based loop
#include <bits/stdc++.h>
#include <iostream>
using namespace std;

// Driver code
int main()
{
int arr[] = {2, -1, 5, 6, 0, -3};

for (const auto &var : arr)


{
cout << var << " " ;
}
return 0;
}
REFERENCES
When a variable is declared as a reference, it becomes an alternative name for
an existing variable. A variable can be declared as a reference by putting ‘&’ in
the declaration.

Applications :

1. Modify the passed parameters in a function: If a function


receives a reference to a variable, it can modify the value of
the variable. For example, the following program variables are
swapped using references.
2. Avoiding a copy of large structures: Imagine a function that has
to receive a large object. If we pass it without reference, a new copy
of it is created which causes wastage of CPU time and memory. We
can use references to avoid this.
3. For Each Loop to avoid the copy of objects: We can use
references in each loop to avoid a copy of individual objects when
objects are large.

In C++, function parameters are variables that are used to pass data into
a function when it is called. Function parameters are defined in the
function's declaration and are used to receive the data that is passed to
the function when it is called.

Function parameters can be either pass-by-value or pass-by-reference.


Pass-by-value means that the function receives a copy of the data that is
passed to it, while pass-by-reference means that the function receives a
reference to the original data.

Passing parameters by reference can be more efficient than pass-by-value


because it avoids the overhead of creating and copying the data.
However, it is important to be careful when using pass-by-reference, as it
can lead to unintended side effects if the function modifies the original
data.

When you pass a parameter by reference to a function, you are essentially


giving the function a direct reference to the original data. This means that
the function can modify the original data directly, rather than working with
a copy of the data.

While passing parameters by reference can be more efficient, it can also


lead to unintended side effects if the function modifies the original data.
To avoid unintended side effects when using pass-by-reference, it is
important to carefully consider whether the function needs to modify the
original data or if it can work with a copy of the data. In general, pass-by-
reference should only be used if the function needs to modify the original
data, as it can lead to unintended consequences if the function modifies
the data in unexpected ways.

Vectors in C++ are part of the Standard Template Library (STL) and provide a dynamic array
functionality, which can grow and shrink in size as needed. Here are some key aspects of
using vectors in C++:

1. Declaration and Initialization

You can declare a vector of a specific type using the std::vector template class.

cpp
Copy code
#include <iostream>
#include <vector>

int main() {
std::vector<int> numbers; // Declare a vector of integers
std::vector<int> numbers2(10); // Declare a vector of integers with
size 10, initialized to 0
std::vector<int> numbers3 = {1, 2, 3, 4, 5}; // Initialize with a list
of values

return 0;
}

2. Adding Elements

Elements can be added to a vector using the push_back() method.

cpp
Copy code
#include <iostream>
#include <vector>

int main() {
std::vector<int> numbers;
numbers.push_back(1);
numbers.push_back(2);
numbers.push_back(3);

for (int num : numbers) {


std::cout << num << " ";
}

return 0;
}

3. Accessing Elements

You can access elements using the [] operator or the at() method.

cpp
Copy code
#include <iostream>
#include <vector>

int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5};

std::cout << numbers[0] << std::endl; // Access the first element


std::cout << numbers.at(1) << std::endl; // Access the second element
using at()

return 0;
}

4. Iterating Over a Vector

You can use a range-based for loop or iterators to iterate over the elements of a vector.

cpp
Copy code
#include <iostream>
#include <vector>

int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5};

// Using range-based for loop


for (int num : numbers) {
std::cout << num << " ";
}
std::cout << std::endl;

// Using iterators
for (std::vector<int>::iterator it = numbers.begin(); it !=
numbers.end(); ++it) {
std::cout << *it << " ";
}

return 0;
}

5. Removing Elements

You can remove elements using the pop_back() method, or using the erase() method for
more control.

cpp
Copy code
#include <iostream>
#include <vector>
int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5};

numbers.pop_back(); // Remove the last element

numbers.erase(numbers.begin() + 1); // Remove the second element

for (int num : numbers) {


std::cout << num << " ";
}

return 0;
}

6. Capacity and Size

Vectors have various methods to query their capacity and size.

cpp
Copy code
#include <iostream>
#include <vector>

int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5};

std::cout << "Size: " << numbers.size() << std::endl; // Get the
number of elements
std::cout << "Capacity: " << numbers.capacity() << std::endl; // Get
the capacity of the vector
std::cout << "Is empty: " << std::boolalpha << numbers.empty() <<
std::endl; // Check if the vector is empty

return 0;
}

7. Resizing a Vector

You can change the size of a vector using the resize() method.

cpp
Copy code
#include <iostream>
#include <vector>

int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5};

numbers.resize(3); // Resize to contain only the first 3 elements

for (int num : numbers) {


std::cout << num << " ";
}

return 0;
}
8. Clearing a Vector

To remove all elements from a vector, use the clear() method.

cpp
Copy code
#include <iostream>
#include <vector>

int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5};

numbers.clear(); // Remove all elements

std::cout << "Size after clearing: " << numbers.size() << std::endl;

return 0;
}

Summary

Vectors in C++ are versatile and powerful containers that handle dynamic arrays with ease.
They provide various methods to manipulate and access the data efficiently, making them an
essential tool in any C++ programmer's toolkit.

The #include <map> directive in C++ includes the map container from the Standard
Template Library (STL). A map is an associative container that stores key-value pairs, where
each key is unique and is used to associate with its corresponding value. Here are some key
aspects of using maps in C++:

1. Declaration and Initialization

You can declare a map by specifying the types for the key and the value.

cpp
Copy code
#include <iostream>
#include <map>

int main() {
std::map<int, std::string> idToName; // Declare a map with integer
keys and string values
std::map<std::string, int> wordCount = {{"hello", 1}, {"world",
2}}; // Initialize with a list of key-value pairs

return 0;
}

2. Adding Elements

Elements can be added to a map using the operator[] or the insert() method.

cpp
Copy code
#include <iostream>
#include <map>

int main() {
std::map<int, std::string> idToName;
idToName[1] = "Alice";
idToName[2] = "Bob";

idToName.insert({3, "Charlie"}); // Using insert with an initializer


list

for (const auto& pair : idToName) {


std::cout << pair.first << ": " << pair.second << std::endl;
}

return 0;
}

3. Accessing Elements

You can access elements using the operator[] or the at() method.

cpp
Copy code
#include <iostream>
#include <map>

int main() {
std::map<int, std::string> idToName = {{1, "Alice"}, {2, "Bob"}};

std::cout << idToName[1] << std::endl; // Access the value with key 1
std::cout << idToName.at(2) << std::endl; // Access the value with key
2 using at()

return 0;
}

4. Iterating Over a Map

You can use a range-based for loop or iterators to iterate over the elements of a map.

cpp
Copy code
#include <iostream>
#include <map>

int main() {
std::map<int, std::string> idToName = {{1, "Alice"}, {2, "Bob"}, {3,
"Charlie"}};

// Using range-based for loop


for (const auto& pair : idToName) {
std::cout << pair.first << ": " << pair.second << std::endl;
}

// Using iterators
for (std::map<int, std::string>::iterator it = idToName.begin(); it !=
idToName.end(); ++it) {
std::cout << it->first << ": " << it->second << std::endl;
}

return 0;
}

5. Removing Elements

You can remove elements using the erase() method.

cpp
Copy code
#include <iostream>
#include <map>

int main() {
std::map<int, std::string> idToName = {{1, "Alice"}, {2, "Bob"}, {3,
"Charlie"}};

idToName.erase(2); // Remove the element with key 2

for (const auto& pair : idToName) {


std::cout << pair.first << ": " << pair.second << std::endl;
}

return 0;
}

6. Finding Elements

You can find elements using the find() method, which returns an iterator to the element if
found, or to map::end if not.

cpp
Copy code
#include <iostream>
#include <map>

int main() {
std::map<int, std::string> idToName = {{1, "Alice"}, {2, "Bob"}, {3,
"Charlie"}};

auto it = idToName.find(2);
if (it != idToName.end()) {
std::cout << "Found: " << it->first << ": " << it->second <<
std::endl;
} else {
std::cout << "Not found" << std::endl;
}

return 0;
}

7. Size and Empty

You can check the size of a map and whether it is empty using the size() and empty()
methods.
cpp
Copy code
#include <iostream>
#include <map>

int main() {
std::map<int, std::string> idToName = {{1, "Alice"}, {2, "Bob"}, {3,
"Charlie"}};

std::cout << "Size: " << idToName.size() << std::endl; // Get the
number of elements
std::cout << "Is empty: " << std::boolalpha << idToName.empty() <<
std::endl; // Check if the map is empty

return 0;
}

Summary

Maps in C++ are efficient for scenarios where you need to associate unique keys with
specific values. They provide various methods to manipulate and access the data, making
them a fundamental part of the STL for managing associative arrays.

C++ 17 or higher: Range-based loops can also be used with maps like
this:

for (auto& [key, value]: myMap) {


cout << key << " has value " << value << std::endl;
}
In C++, you can use the const keyword to declare a reference that cannot be
modified, and you can use the && operator to declare an rvalue reference, which
is a reference to a temporary object that will be destroyed after the reference
goes out of scope.

#include <iostream>
using namespace std;

// function that takes an rvalue reference to an integer as input


void printNumber(int &&x) {
cout << x << endl;
}

int main() {
printNumber(3);
return 0;
}

In this example, the function printNumber() takes an rvalue reference to an


integer as input. This means that the function receives a reference to a
temporary object that will be destroyed after the reference goes out of scope.
The function is called from the main() function with the value 3, and the value is
printed to the screen.
LVALUES AND R VALUES:

Lvalues

An lvalue (locator value) refers to an object that occupies some identifiable location in
memory (i.e., it has an address). Lvalues can appear on the left-hand side or the right-hand
side of an assignment.

Examples of Lvalues:

1. Variables:

cpp
Copy code
int x = 10; // x is an lvalue
x = 20; // Valid: x can be assigned a new value

2. Dereferenced Pointers:

cpp
Copy code
int x = 10;
int* p = &x;
*p = 20; // *p is an lvalue referring to x

3. Array Elements:

cpp
Copy code
int arr[3] = {1, 2, 3};
arr[0] = 10; // arr[0] is an lvalue

4. Class Members:

cpp
Copy code
struct Point {
int x;
int y;
};

Point p;
p.x = 10; // p.x is an lvalue

Rvalues

An rvalue (right value) is an expression that does not refer to a memory location and is
typically a temporary value that doesn't persist beyond the expression that uses it. Rvalues
can only appear on the right-hand side of an assignment.
Examples of Rvalues:

1. Literals:

cpp
Copy code
int x = 42; // 42 is an rvalue

2. Temporary Objects:

cpp
Copy code
int y = x + 1; // x + 1 is an rvalue

3. Function Return Values:

cpp
Copy code
int foo() {
return 42; // 42 is an rvalue
}

int z = foo(); // foo() is an rvalue

Lvalues vs. Rvalues in Expressions

 Lvalues: Can appear on the left-hand side or right-hand side of an assignment.

cpp
Copy code
int x = 10;
x = 20; // x is an lvalue on the left-hand side of the assignment
int y = x; // x is an lvalue on the right-hand side of the
assignment

 Rvalues: Can only appear on the right-hand side of an assignment.

cpp
Copy code
int x = 10;
int y = x + 5; // x + 5 is an rvalue

Modifiable vs. Non-modifiable Lvalues

 Modifiable Lvalues: Variables that can be changed.

cpp
Copy code
int x = 10;
x = 20; // x is a modifiable lvalue

 Non-modifiable Lvalues: Variables that cannot be changed (e.g., const variables).

cpp
Copy code
const int x = 10;
// x = 20; // Error: x is a non-modifiable lvalue

Lvalue References vs. Rvalue References

 Lvalue References: Used to refer to lvalues.

cpp
Copy code
int x = 10;
int& ref = x; // ref is an lvalue reference to x
ref = 20;

 Rvalue References: Introduced in C++11, used to refer to rvalues, enabling move


semantics and perfect forwarding.

cpp
Copy code
int&& rref = 10; // rref is an rvalue reference to the rvalue 10

Summary

 Lvalue: An expression that refers to a memory location and can appear on both sides of an
assignment.
 Rvalue: A temporary value that cannot appear on the left-hand side of an assignment.
 Modifiable Lvalue: A lvalue that can be changed.
 Non-modifiable Lvalue: A lvalue that cannot be changed (e.g., const variables).
 Lvalue References: Used to refer to lvalues.
 Rvalue References: Used to refer to rvalues (introduced in C++11).

Understanding the difference between lvalues and rvalues is crucial for mastering C++
programming, especially when dealing with advanced topics like move semantics and perfect
forwarding.

When a function returns by reference it can be used as l value.


POINTERS
In C++, the address operator & is used to obtain the memory address of a
variable. For example, if x is a variable, the expression &x will give you
the memory address of x.

The dereference operator * is used to access the value stored at a


memory address. For example, if ptr is a pointer that stores the memory
address of a variable, the expression *ptr will give you the value stored at
that memory address.

Taking the address of an uninitialized or invalid variable can have serious


consequences for your C++ program. If you take the address of an
uninitialized variable, you may be accessing a random memory location,
which can lead to unpredictable behavior or even a crash. If you take the
address of a variable that has been deallocated, you may cause a
segmentation fault, which will cause the program to crash.

To avoid these problems, it's important to always make sure that a


variable is properly initialized before taking its address. For example:

int x = 5; // initialize x to 5
int* ptr = &x; // take the address of x and store it in ptr
It's also a good idea to be mindful of the lifetime of variables when taking
their address. If a variable goes out of scope or is deallocated, its memory
address is no longer valid, and taking the address of the variable can lead
to undefined behavior. To avoid this problem, make sure that the variable
is still in scope and has not been deallocated before taking its address.

Dereferencing an uninitialized or invalid pointer can have serious


consequences for your C++ program. If you dereference an uninitialized
pointer, you may be accessing a random memory location, which can lead
to unpredictable behavior or even a crash. If you dereference a null
pointer, you may cause a segmentation fault, which will cause the
program to crash.

To avoid these problems, it's important to always make sure that a pointer
is properly initialized and points to a valid memory location before
dereferencing it. One way to do this is to initialize pointers to nullptr,
which is a special value that represents a null pointer:

int* ptr = nullptr; // initialize ptr to a null pointer


You can then check for null pointers before dereferencing them to ensure
that they are valid:
if (ptr != nullptr) // check if ptr is a null pointer
{
*ptr = 10; // dereference ptr
}

Pointers are symbolic representations of addresses. They enable programs


to simulate call-by-reference as well as to create and manipulate dynamic
data structures. Iterating over elements in arrays or other data structures
is one of the main use of pointers.

The address of the variable you’re working with is assigned to the pointer
variable that points to the same data type (such as an int or string).

Features of Pointers:

1. Pointers save memory space.


2. Execution time with pointers is faster because data are manipulated
with the address, that is, direct access to memory location.
3. Memory is accessed efficiently with the pointers. The pointer assigns
and releases the memory as well. Hence it can be said the Memory
of pointers is dynamically allocated.
4. Pointers are used with data structures. They are useful for
representing two-dimensional and multi-dimensional arrays.
5. An array, of any type, can be accessed with the help of pointers,
without considering its subscript range.
6. Pointers are used for file handling.
7. Pointers are used to allocate memory dynamically.
8. In C++, a pointer declared to a base class could access the object of
a derived class. However, a pointer to a derived class cannot access
the object of a base class.
Uses of pointers:

1.
To pass arguments by reference
2.
For accessing array elements
3.
To return multiple values
4.
Dynamic memory allocation
5.
To implement data structures
6.
To do system-level programming where memory addresses are
useful
Drawbacks of Pointers:

 If pointers are pointed to some incorrect location then it may end up


reading a wrong value.
 Erroneous input always leads to an erroneous output
 Segmentation fault can occur due to uninitialized pointer.
 Pointers are slower than normal variable
 It requires one additional dereferences step
 If we forgot to deallocate a memory then it will lead to a memory
leak.

#include <iostream>

void increment(int* x)
{
(*x)++; // increment the value stored at the memory address pointed to
by x
}

int main()
{
int x = 5;
std::cout << "x before increment: " << x << std::endl;

increment(&x); // pass the memory address of x to the increment


function
std::cout << "x after increment: " << x << std::endl;

return 0;
}
Output
x before increment: 5
x after increment: 6
In C++, you can pass arrays as function parameters to modify the elements of
an array in a function.
#include <iostream>

void increment(int arr[], int size)


{
for (int i = 0; i < size; i++)
{
arr[i]++; // increment the value stored at each element of the
array
}
}

int main()
{
int arr[] = { 1, 2, 3, 4, 5 };
int size = sizeof(arr) / sizeof(arr[0]);

increment(arr, size); // pass the array and the size of the array to
the increment function

for (int i = 0; i < size; i++)


{
std::cout << arr[i] << " ";
}

return 0;
}
Output
2 3 4 5 6
the function increment takes an int array and an int as parameters, and
modifies the values stored at each element of the array. This has the
effect of modifying the elements of arr in the main function, even though
arr is not returned by the increment function.

Passing arrays as function parameters can be a useful tool in C++, as it


allows you to modify the elements of an array in a function without
returning the array itself. However, it's important to be careful when
working with arrays, as they can be tricky to work with and can lead to
problems if used incorrectly.
Here are a few tips for working with arrays as function parameters safely
in C++:

 Always initialize arrays before using them to avoid undefined


behavior.
 Check for out-of-bounds accesses to avoid reading or writing to
memory locations that are not part of the array.
 Use array bounds checking tools, such as AddressSanitizer, to
detect and debug array-related errors, such as out-of-bounds
accesses and buffer overflows.
By following these guidelines, you can help ensure that your C++
programs are safe and stable when using arrays as function parameters.

Difference Between Arrays and Pointers in C++

The pointer can be used to access the array elements, accessing the
whole array using pointer arithmetic, makes the accessing faster. The
main difference between Array and Pointers is the fixed size of the
memory block. When Arrays are created the fixed size of the memory
block is allocated. But with Pointers the memory is dynamically allocated.
There are some other differences between an array and a pointer which
are discussed below in the table.

S. No. Array Pointer

1. Arrays are declared as Pointers are declared


type var_name[size]; as type * var_name;
2. Collection of elements of Store the address of
similar data type. another variable.

3. An array can decide the The pointer can store


number of elements it the address of only one
can store. variable.

4. Arrays are allocated at Pointers are allocated


compile time. at run-time.

5. Memory allocation is in Memory allocation is


sequence. random.

6. Arrays are static in Pointers are dynamic in


nature i.e. they cannot nature i.e. memory
be resized according to allocated can be
the user requirements. resized later.

7. An array of pointers can A pointer to an array


be generated. can be generated.

8. An array is a group of Pointer is not a group


elements. of elements.

In C++, the distinction between compile-time and run-time initialization is important for
understanding how variables are set up and used in your programs. Here’s a breakdown of
what is initialized at compile-time versus run-time:

Compile-Time Initialization

Compile-time initialization occurs when the value of a variable is determined at the time the
code is compiled. This typically applies to:
1. Constant Expressions: Values that are known at compile time, such as literals or
expressions that can be evaluated by the compiler.

cpp
Copy code
const int x = 10; // Initialized at compile time
constexpr int y = x + 5; // Also initialized at compile time

2. Global and Static Variables: These variables are initialized before the main program
starts executing.

cpp
Copy code
int globalVar = 100; // Initialized at compile time
static int staticVar = 200; // Initialized at compile time

Run-Time Initialization

Run-time initialization occurs when the value of a variable is determined during the
execution of the program. This includes:

1. Local Variables: Variables declared inside a function and initialized with values
computed at run-time.

cpp
Copy code
int main() {
int a = 5; // Initialized at run time
int b = a * 2; // Initialized at run time
return 0;
}

2. Dynamic Memory Allocation: Memory allocated using new or malloc is initialized


at run-time.

cpp
Copy code
int* ptr = new int(10); // Initialized at run time

3. User Input: Values that are obtained from user input or external sources during the
execution of the program.

cpp
Copy code
int main() {
int userInput;
std::cin >> userInput; // Initialized at run time
return 0;
}

Examples and Explanations

1. Compile-Time Example:
cpp
Copy code
#include <iostream>

constexpr int compileTimeValue() {


return 10;
}

int main() {
constexpr int a = compileTimeValue(); // Compile-time
initialization
std::cout << "Value of a: " << a << std::endl;
return 0;
}

2. Run-Time Example:

cpp
Copy code
#include <iostream>

int runTimeValue() {
return 20;
}

int main() {
int b = runTimeValue(); // Run-time initialization
std::cout << "Value of b: " << b << std::endl;
return 0;
}

Summary

 Compile-Time Initialization: Happens for constant expressions, global/static


variables, and constexpr variables/functions. These are set during compilation.
 Run-Time Initialization: Happens for local variables, dynamic memory allocation,
and any variable set based on run-time data (e.g., user input). These are set when the
program is running.

Understanding this distinction helps in optimizing programs and ensuring correct behavior,
especially in performance-critical applications.

In C++, the NULL macro represents a null pointer, which is a special pointer value that
indicates that the pointer does not point to a valid memory location. A null pointer does not
point to any object or memory location, and dereferencing a null pointer can cause a runtime
error or crash.

Here is an example of how the NULL macro can be used in C++:

C++
#include <iostream>
int main()
{
int* ptr = NULL; // initialize ptr to NULL

if (ptr == NULL) // check if ptr is a null pointer


{
std::cout << "ptr is a null pointer" << std::endl;
}

return 0;
}

Output
ptr is a null pointer
the NULL macro is used to initialize the pointer ptr to a null pointer, and to check if ptr is a
null pointer.

It's important to be careful when working with null pointers in C++, as dereferencing a null
pointer can cause a runtime error or crash. Make sure to always check for null pointers before
dereferencing them to avoid these problems.

In C++11 and later, the nullptr keyword is preferred over the NULL macro for representing
null pointers. The nullptr keyword is a null pointer literal that is guaranteed to be of
type nullptr_t, which is a distinct type that is not implicitly convertible to any other type.
This helps avoid problems with the NULL macro, which is often defined as a constant
integer value, and can be accidentally converted to an integer type in certain contexts.

There are several common use cases for the NULL macro in C++:

 Initializing pointers to null: The NULL macro is often used to initialize pointers to a
null pointer value, indicating that the pointer does not point to a valid memory
location. This can be useful to prevent dereferencing uninitialized pointers, which can
lead to runtime errors or crashes.
 Checking for null pointers: The NULL macro is often used to check if a pointer is a
null pointer, which can be useful to avoid dereferencing null pointers and causing
runtime errors or crashes.
 Providing a default value for pointers: The NULL macro is sometimes used as a
default value for pointers, indicating that the pointer does not point to a valid memory
location. This can be useful in situations where a pointer may not always be
initialized, such as in function arguments or class member variables.
 Representing the absence of an object: In some cases, the NULL macro is used to
represent the absence of an object, such as in linked lists or trees where a null pointer
indicates the end of the list or the absence of a child node.
The value of the NULL macro is implementation-defined and may vary depending on the
platform and compiler being used. In most cases, the NULL macro is defined as a constant
integer value that is equal to zero, such as #define NULL 0.
// This program compiles
#include<iostream>
using namespace std;

int main()
{
int *ptr = nullptr;

// Below line compiles


if (ptr) { cout << "true"; }
else { cout << "false"; }
}
Output
false

A limited set of arithmetic operations can be performed on pointers which


are:

 incremented ( ++ )
 decremented ( — )
 an integer may be added to a pointer ( + or += )
 an integer may be subtracted from a pointer ( – or -= )
 difference between two pointers (p1-p2)
(Note: Pointer arithmetic is meaningless unless performed on an array.)

// C++ program to illustrate Pointer Arithmetic


#include <bits/stdc++.h>
using namespace std;
void geeks()
{
// Declare an array
int v[3] = { 10, 100, 200 };

// declare pointer variable


int* ptr;

// Assign the address of v[0] to ptr


ptr = v;

for (int i = 0; i < 3; i++) {


cout << "Value at ptr = " << ptr << "\n";
cout << "Value at *ptr = " << *ptr << "\n";

// Increment pointer ptr by 1


ptr++;
}
}

// Driver program
int main() { geeks(); }

Dynamic memory allocation in 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;

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++
// 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
Marked as Read
Report An Issue
The functions cin and getline are both used in C++ for input operations but serve different
purposes and have distinct behaviors.

cin

 Purpose: Used to read input from the standard input (usually the keyboard).
 Type: Reads formatted input.
 Usage:

cpp
Copy code
int age;
std::cin >> age;

 Behavior:
o Stops reading at the first whitespace character (space, tab, newline).
o Suitable for reading single word or number inputs.
o Ignores leading whitespace characters.

getline

 Purpose: Used to read an entire line of text from the standard input.
 Type: Reads unformatted input.
 Usage:

cpp
Copy code
std::string name;
std::getline(std::cin, name);

 Behavior:
o Reads characters until a newline character is encountered.
o Includes leading and trailing whitespace characters in the input.
o More suitable for reading strings that may contain spaces, like full names or
sentences.

Key Differences

1. Stopping Condition:
o cin stops reading at the first whitespace.
o getline stops reading at a newline character.
2. Handling Whitespace:
o cin skips leading whitespace and stops at the first whitespace after the input.
o getline includes all whitespace characters in the input.
3. Use Case:
o cin is ideal for simple, single-value inputs (like an integer or a single word).
o getline is ideal for capturing entire lines of text (like a full sentence or
multiple words).

Example of Combined Use


When using getline after cin, you might encounter an issue where getline reads an empty
line. This happens because cin leaves a newline character in the input buffer. To handle this,
you can use std::cin.ignore():

cpp
Copy code
#include <iostream>
#include <string>

int main() {
int age;
std::string name;

std::cout << "Enter your age: ";


std::cin >> age;
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); //
Clear the newline character from the buffer

std::cout << "Enter your name: ";


std::getline(std::cin, name);

std::cout << "Name: " << name << ", Age: " << age << std::endl;

return 0;
}

In this example:

 cin reads the age.


 std::cin.ignore() clears the leftover newline character.
 getline reads the entire line of text for the name.

Understanding these differences allows you to choose the appropriate function based on your
input needs in a C++ program.

The std::flush manipulator in C++ is used to flush the output buffer of a stream. When you
use std::flush, it forces the buffer associated with the stream to be flushed to its
destination. This is particularly useful in the following scenarios:

1. Immediate Output: If you want to ensure that something is immediately output to


the console or a file, you can use std::flush. For example, in interactive programs
where user feedback is important, flushing the output buffer ensures that messages are
displayed without delay.

literals are "directly represented in code," we mean that these values are explicitly written out in the
source code rather than being stored in variables or derived from expressions. These are the raw,
fixed values that the program uses.

1. Integer Literals: When you write 42 in your code, it is directly understood by the
compiler as the integer value 42. There's no need for computation or variable
assignment; the number 42 is exactly what it appears to be.

cpp
Copy code
int a = 42; // Here, 42 is a literal.

2. Floating-Point Literals: Writing 3.14 in your code represents the floating-point


value 3.14. This is a precise value written directly in the source code.

cpp
Copy code
double pi = 3.14; // Here, 3.14 is a literal.

3. Character Literals: Writing 'a' in your code directly represents the character a.
This is not a variable or an expression; it’s the character a itself.

cpp
Copy code
char letter = 'a'; // Here, 'a' is a literal.

4. String Literals: When you write "Hello, World!", it directly represents a sequence
of characters. The entire string is embedded in the code as is.

cpp
Copy code
const char* greeting = "Hello, World!"; // Here, "Hello, World!" is
a literal.

5. Boolean Literals: The values true and false are directly understood by the
compiler as boolean values.

cpp
Copy code
bool isTrue = true; // Here, true is a literal.

6. Null Pointer Literal: Writing nullptr directly represents a null pointer value.

cpp
Copy code
int* ptr = nullptr; // Here, nullptr is a literal.

Practical Implications

The direct representation of literals in code means:

 Immediate Recognition: The compiler immediately understands and recognizes


these values without any need for computation.
 Fixed Values: The values are fixed and immutable within the code. They are
constants by nature.
 Readability: Literals make the code easier to read and understand because the values
are directly visible in the code.

Example to Illustrate

Consider the following code:

cpp
Copy code
#include <iostream>

int main() {
int age = 25; // 25 is an integer literal
double pi = 3.14159; // 3.14159 is a floating-point literal
char grade = 'A'; // 'A' is a character literal
const char* message = "Hello"; // "Hello" is a string literal
bool isValid = true; // true is a boolean literal
int* ptr = nullptr; // nullptr is a null pointer literal

std::cout << "Age: " << age << std::endl;


std::cout << "Pi: " << pi << std::endl;
std::cout << "Grade: " << grade << std::endl;
std::cout << "Message: " << message << std::endl;
std::cout << "Is Valid: " << isValid << std::endl;
std::cout << "Pointer: " << ptr << std::endl;

return 0;
}

In this example:

 25 is directly written in the code as an integer literal.


 3.14159 is directly written in the code as a floating-point literal.
 'A' is directly written in the code as a character literal.
 "Hello" is directly written in the code as a string literal.
 true is directly written in the code as a boolean literal.
 nullptr is directly written in the code as a null pointer literal.

These values are embedded directly in the source code, representing specific fixed values the
program uses. They do not need to be computed or retrieved from somewhere else—they are
the exact values as written.

The constexpr keyword in C++ is used to declare that a variable, function, or constructor
can be evaluated at compile time. This allows the compiler to compute values during
compilation, which can improve performance and enable certain optimizations. Here’s a
detailed look at constexpr:

constexpr Variables

Definition:

 constexpr variables are constants whose values are known and computed at compile
time.

Characteristics:

 Compile-Time Evaluation: The value of a constexpr variable is computed at


compile time.
 Constant Expression: Must be initialized with a constant expression—something
that can be evaluated during compilation.
Example:

cpp
Copy code
constexpr int maxSize = 100; // Must be a compile-time constant

constexpr Functions

Definition:

 Functions declared with constexpr are functions that can be evaluated at compile
time if all their arguments are compile-time constants.

Characteristics:

 Compile-Time Computation: constexpr functions can be used in contexts requiring


compile-time constant expressions.
 Usage in Expressions: They can be used wherever compile-time constants are
allowed, such as in array sizes, template parameters, etc.

Example:

cpp
Copy code
constexpr int square(int x) {
return x * x;
}

constexpr int result = square(5); // Result is evaluated at compile time

constexpr Constructors

Definition:

 constexpr constructors allow objects of a class to be initialized at compile time.

Characteristics:

 Compile-Time Object Creation: Objects can be created and initialized at compile


time if the constructor and all its arguments are constexpr.

Example:

cpp
Copy code
class MyClass {
public:
constexpr MyClass(int x) : value(x) {}
constexpr int getValue() const { return value; }

private:
int value;
};
constexpr MyClass obj(10); // Object is created and initialized at compile
time
constexpr int val = obj.getValue(); // Value is evaluated at compile time

Rules for constexpr

1. Initialization: constexpr variables must be initialized with constant expressions.


They can be used in constant expressions themselves.
2. Function Limitations: constexpr functions can contain return statements, but they
cannot contain non-constant expressions or statements that depend on runtime
information.
3. Complexity: Starting from C++14, constexpr functions can contain more complex
statements like loops and conditionals, as long as they still produce compile-time
constants when used with constant expressions.
4. constexpr vs. const: While both const and constexpr imply immutability,
constexpr additionally ensures compile-time evaluation. All constexpr variables
are const, but not all const variables are constexpr.

Example Comparison

const Example:

cpp
Copy code
const int runtimeValue = getRuntimeValue(); // Initialized at runtime

constexpr Example:

cpp
Copy code
constexpr int compileTimeValue = 42; // Evaluated at compile time
constexpr int squaredValue = square(6); // Evaluated at compile time

Summary

 constexpr Variables: Must be initialized with constant expressions; their values are
determined at compile time.
 constexpr Functions: Can be evaluated at compile time when given constant
arguments; useful for compile-time computations.
 constexpr Constructors: Allow objects to be initialized at compile time if the
constructor and its parameters are constant expressions.

constexpr enhances performance and flexibility by ensuring that certain values and
computations are resolved during compilation, leading to more efficient and potentially more
optimized code.
Definition:

 constinit is a keyword introduced in C++20 to ensure that a variable is initialized at


compile time but does not impose any restriction on its mutability after initialization.

Purpose:

 The primary purpose of constinit is to ensure that a variable is initialized before any
dynamic initialization happens (i.e., before the program’s execution starts), but unlike
constexpr, it does not require the variable to be immutable or used in constant
expressions.

Key Characteristics

1. Initialization at Compile Time:


o Variables declared with constinit are guaranteed to be initialized at compile
time, ensuring that their initialization is complete before any other code
executes.
2. Mutable Variables:
o Unlike constexpr, constinit does not make the variable immutable. It
simply ensures that the variable’s initialization is done at compile time.
3. Non-Constant Expressions:
o constinit variables do not have to be initialized with constant expressions.
They can be initialized with values or expressions that are not strictly compile-
time constants, but they still must be initialized before the program starts.

Example

Using constinit:

cpp
Copy code
constinit int myValue = 10; // Ensures initialization at compile time, but
'myValue' can be modified

In this example, myValue will be initialized at compile time, but unlike constexpr, it can be
changed later in the code.

Comparison with const and constexpr:

 const:
o Ensures immutability after initialization but does not require compile-time
initialization.
o Example: const int x = 5; (x can be initialized at runtime.)
 constexpr:
o Requires compile-time evaluation and ensures immutability.
o Example: constexpr int y = 10; (y must be initialized with a compile-time
constant.)
 constinit:
o Ensures compile-time initialization but does not imply immutability.
o Example: constinit int z = 20; (z is initialized at compile time and can
be modified.)

Summary

 const: Guarantees immutability but does not enforce compile-time initialization.


 constexpr: Guarantees both compile-time initialization and immutability.
 constinit: Ensures compile-time initialization but does not guarantee immutability
or require compile-time constants for initialization.

constinit is particularly useful for variables that must be initialized at compile time but
where immutability is not a requirement. It provides flexibility for cases where compile-time
initialization is crucial, but runtime modification of the variable’s value is still needed.

Static Storage Duration: Variables with static storage duration are initialized once and exist for the
lifetime of the program. constinit can be used with these variables to ensure they are initialized
at compile time.

The std namespace is a special namespace that contains all the classes, objects, and functions of the
C++ Standard Library.

If you want to use std::getline with an std::string, use the standard getline function.
Here’s how you can use both methods correctly:

Using std::getline with std::string


cpp
Copy code
#include <iostream>
#include <string>

int main() {
std::string line;
std::cout << "Enter a line of text: ";
std::getline(std::cin, line); // Read the entire line as a string
std::cout << "You entered: " << line << std::endl;
return 0;
}

Using std::cin.getline with a C-Style Character Array

If you want to limit the number of characters read, you need to use a character array:

cpp
Copy code
#include <iostream>

int main() {
char line[6]; // Create a character array with a size of 6
std::cout << "Enter a line of text: ";
std::cin.getline(line, 6); // Read up to 5 characters (6th is for null
terminator)
std::cout << "You entered: " << line << std::endl;
return 0;
}

Explanation

 std::getline(std::cin, line);: Reads an entire line of text into an


std::string.
 std::cin.getline(line, 6);: Reads up to 5 characters into a C-style character
array (the 6th character is reserved for the null terminator).

Here’s the revised example using std::string and std::getline correctly:

cpp
Copy code
#include <iostream>
#include <string>

int main() {
std::string line;
std::cout << "Enter a line of text: ";
std::getline(std::cin, line); // Use std::getline with std::string
std::cout << "You entered: " << line << std::endl;
return 0;
}

Or, if you want to limit the input to a certain number of characters and use a C-style character
array:

cpp
Copy code
#include <iostream>

int main() {
char line[6]; // Define a character array with a size of 6
std::cout << "Enter a line of text (max 5 characters): ";
std::cin.getline(line, 6); // Read up to 5 characters
std::cout << "You entered: " << line << std::endl;
return 0;
}

Use std::getline for dynamic strings with no fixed length, and std::cin.getline for
fixed-size character arrays with a specified limit.

When you work with arrays in C++, p and &p can indeed produce similar addresses but
represent different types. Here’s what happens in your code snippet:

cpp
Copy code
#include<iostream>
using namespace std;

int main() {
int p[] = {1, 2, 3};
cout << p << endl;
cout << &p << endl;
}

Let’s break down the output:

1. cout << p << endl;


o p is an array of int. When you use p in this context, it decays to a pointer to
the first element of the array. This prints the address of the first element of the
array p.
2. cout << &p << endl;
o &p is the address of the entire array p, and its type is int (*)[3], which is a
pointer to the entire array. This prints the address of the array p as a whole.

In this particular case, p and &p will usually print the same address, because p decays to a
pointer to the first element, and &p provides the address of the array. However, the types of
these expressions are different:

 p is of type int* (pointer to the first element).


 &p is of type int(*)[3] (pointer to the whole array of 3 integers).
Each of the above methods is discussed below:

1. C style string: In C, strings are defined as an array of characters.


The difference between a character array and a string is the string is
terminated with a special character ‘\0’. In C, the string is actually
represented as an array of characters terminated by a null string.
Therefore the size of the character array is always one more than
that of the number of characters in the actual string. This thing
continues to be supported in C++ too. The C++ compiler
automatically sets “\0” at the end of the string, during initialization
of the array.
Initializing a String in C++:

1. char str[] = "Geeks";


2. char str[6] = "Geeks";
3. char str[] = {'G', 'e', 'e', 'k', 's', '\0'};
4. char str[6] = {'G', 'e', 'e', 'k', 's', '\0'};
Below is the memory representation of a string “Geeks” in C++.

Let’s look at some examples to better understand the string


representation in C++, using C style:

C++
// C++ program to demonstrate
// Strings using C style

#include <iostream>
using namespace std;

int main()
{

// Declare and initialize string


char str[] = "Geeks";

// Print string
cout << str;

return 0;
}

Output
Geeks
Standard String representation and String Class: In C++, one can
directly store the collection of characters or text in a string variable,
surrounded by double-quotes. C++ provides string class, which supports
various operations like copying strings, concatenating strings etc.

Initializing string in C++:

1. string str1 = "Geeks";


2. string str2 = "Welcome to GeeksforGeeks!";
Example:

C++
// C++ program to demonstrate String
// using Standard String representation

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

int main()
{

// Declare and initialize the string


string str1 = "Welcome to GeeksforGeeks!";

// Initialization by raw string


string str2("A Computer Science Portal");

// Print string
cout << str1 << endl << str2;

return 0;
}

Output
Welcome to GeeksforGeeks!
A Computer Science Portal

In C, strings are defined as an array of characters. The difference between


a character array and a string is the string is terminated with a special
character ‘\0’. In C, the string is actually represented as an array of
characters terminated by a null string. Therefore the size of the character
array is always one more than that of the number of characters in the
actual string. This thing continues to be supported in C++ too. The C++
compiler automatically sets “\0” at the end of the string, during
initialization of the array.

Initializing a String in C++:

1. char str[] = "Geeks";


2. char str[6] = "Geeks";
3. char str[] = {'G', 'e', 'e', 'k', 's', '\0'};
4. char str[6] = {'G', 'e', 'e', 'k', 's', '\0'};
Below is the memory representation of a string “Geeks” in C++.

In C++, the std::string class provides several member functions and


operators for performing common string operations, such as finding the
length of a string, extracting substrings, and searching for substrings
within a string. Here are a few examples of common string operations in
C++:

1. Finding the length of a string: To find the length of a string, you can
use the length member function of the std::string class.
The length function returns the number of characters in the string,
not including the null terminator.
For example:

C++
#include <iostream>
#include <string>

int main()
{
std::string str = "hello";

std::cout << "The length of the string is " << str.length() << "
characters." << std::endl;

return 0;
}

Output
The length of the string is 5 characters.
2.Extracting a substring: To extract a substring from a string, you can
use the substr member function of the std::string class.
The substr function takes two arguments: the starting position
of the substring, and the length of the substring.

For example:

C++
#include <iostream>
#include <string>

int main()
{
std::string str = "hello world";

std::string sub = str.substr(6, 5); // extract the substring starting


at position 6 with a length of 5 characters

std::cout << "The substring is: " << sub << std::endl;

return 0;
}

Output
The substring is: world
Searching for a substring: To search for a substring within a string, you
can use the find member function of the std::string class. The find function
searches for a given substring within a string and returns the position of
the first occurrence of the substring, or `std::string::n

The find function takes two arguments: the substring to search for, and
the starting position of the search. By default, the search starts at the
beginning of the string, but you can specify a different starting position if
you want to search only a portion of the string.

Here is an example of how to use the find function to search for a


substring within a string starting at a specific position:

C++
#include <iostream>
#include <string>

int main()
{
std::string str = "hello world";
std::size_t pos = str.find("l", 3); // search for the first occurrence
of 'l' starting at position 3

if (pos != std::string::npos) // check if the substring was found


{
std::cout << "The substring was found at position " << pos <<
std::endl;
}
else
{
std::cout << "The substring was not found." << std::endl;
}

return 0;
}

Output
The substring was found at position 3
Note that the find function is case-sensitive, so it will only find substrings
that match the case of the search string. If you want to perform a case-
insensitive search, you can use the find function in combination with
the tolower or toupper functions from the cctype library.

C++
#include <cctype> // include the cctype library for tolower and toupper
#include <iostream>
#include <string>

int main()
{
std::string str = "Hello World";

std::string search_string = "world";


for (char& c : search_string) // convert the search string to
lowercase
{
c = std::tolower(c);
}

std::size_t pos = str.find(search_string); // search for the lowercase


version of the search string

if (pos != std::string::npos) // check if the substring was found


{
std::cout << "The substring was found at position " << pos <<
std::endl;
}
else
{
std::cout << "The substring was not found." << std::endl;
}
return 0;
}

Output
The substring was not found.
Reading a string with spaces in C++ can be a bit tricky, as the standard cin function and
the getline() function behave differently when it comes to handling whitespace characters. In
this article, we'll discuss two common methods for reading strings with spaces in C++:
using getline() and using cin with the ignore() function.

Method 1: Using getline() The getline() function is specifically designed to read a line of
text, including any whitespace characters that may be present. It takes two parameters: an
input stream (such as cin) and a string variable to store the input. Here's an example of how
to use getline() to read a string with spaces:

C++
#include <iostream>
#include <string>
using namespace std;

int main() {
string input;
cout << "Enter a string with spaces: ";
getline(cin, input);
cout << "You entered: " << input << endl;
return 0;
}

Method 2: Using cin with the ignore() function


Another method for reading strings with spaces is to use cin to read individual words, but
then use the ignore() function to discard the remaining whitespace characters in the input
stream. The ignore() function takes two parameters: an input stream and the number of
characters to ignore. Here's an example of how to use cin and ignore() to read a string with
spaces:

C++
#include <iostream>
#include <string>
using namespace std;

int main() {
string input;
cout << "Enter a string with spaces: ";
cin >> input;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
getline(cin, input);
cout << "You entered: " << input << endl;
return 0;
}

Both of the above methods will allow you to read a string with spaces in C++. However, it's
important to note that using the cin with ignore() will ignore the characters in the input
stream until the given number of characters, specified in the second parameter
of ignore() function, or until a newline character ('\n') is encountered.

When using getline(), you should be careful to remember that the newline character at the
end of the input will be included in the string, which may cause problems if you're expecting
the string not to contain a newline character.

Note that we have only discussed Method 1 as it is the one


which is widely used and
accepted.
It's also worth noting that if you expect multiple lines of input to be passed, it's better to
use getline() as it's designed to read entire lines of input, whereas cin is designed to read
individual words.

In conclusion, both method can be used for reading strings with spaces in C++ but the
appropriate method should be chosen according to the requirement of the problem.

A modifier function (or mutator function) is a type of function that alters the state or
content of an object. In the context of the std::string class in C++, modifier functions are
those that change the actual content, size, or properties of a string object.

Characteristics of Modifier Functions:

1. Change the State: They modify the data members (like the characters in a string) or
properties of the object they are called on.
2. Non-const: Since they modify the object, they are not marked as const and cannot be
called on const objects.
3. Return Type: Some modifier functions return the modified object itself (to allow for
method chaining), while others may return void or other relevant data.

Examples in std::string:

 append(): Adds characters to the end of the string.

cpp
Copy code
std::string str = "Hello";
str.append(" World"); // str becomes "Hello World"

 insert(): Inserts characters at a specific position in the string.

cpp
Copy code
std::string str = "Hello!";
str.insert(5, ", World"); // str becomes "Hello, World!"

 erase(): Removes characters from the string.

cpp
Copy code
std::string str = "Hello, World!";
str.erase(5, 7); // str becomes "Hello"

 replace(): Replaces a portion of the string with new content.

cpp
Copy code
std::string str = "Hello, World!";
str.replace(7, 5, "Universe"); // str becomes "Hello, Universe!"

 clear(): Empties the string, making it an empty string.

cpp
Copy code
std::string str = "Hello!";
str.clear(); // str becomes ""

 resize(): Changes the size of the string, adding or removing characters.

cpp
Copy code
std::string str = "Hello";
str.resize(10, '!'); // str becomes "Hello!!!!!"

 push_back(): Adds a single character to the end of the string.

cpp
Copy code
std::string str = "Hello";
str.push_back('!'); // str becomes "Hello!"

 pop_back(): Removes the last character from the string.

cpp
Copy code
std::string str = "Hello!";
str.pop_back(); // str becomes "Hello"
In C++, a macro is a preprocessor directive that allows you to define a piece of code that can
be reused throughout your program. Macros are created using the #define directive, and they
essentially perform a text substitution before the compilation process begins.

There are two main types of macros in C++:

1. Object-like macros: These are simple text replacements. For example:

cpp
Copy code
#define PI 3.14159

In this case, every occurrence of PI in the code will be replaced by 3.14159 during
preprocessing.

2. Function-like macros: These resemble function calls but perform simple textual
replacements and do not involve any actual function call overhead. For example:

cpp
Copy code
#define SQUARE(x) ((x) * (x))

This macro takes an argument x and replaces SQUARE(x) with ((x) * (x)) wherever
it appears in the code.

Key Points to Remember About Macros

 No Type Checking: Macros do not perform type checking, which means they can
lead to errors if not used carefully. For example, SQUARE(1 + 2) will be replaced by
((1 + 2) * (1 + 2)), which expands to ((3) * (3)), giving the correct result.
However, without careful use of parentheses in the macro definition, such as #define
SQUARE(x) x * x, the expansion would result in 1 + 2 * 1 + 2, which evaluates
incorrectly due to operator precedence.
 Scope and Lifetime: Macros are not affected by scopes in the same way as variables
and functions. Once defined, they are globally replaced throughout the entire code file
until they are explicitly undefined using #undef.
 Use in Conditional Compilation: Macros are often used for conditional compilation
using preprocessor directives like #ifdef, #ifndef, #if, #else, #elif, and #endif.
This allows certain parts of the code to be compiled or ignored based on whether a
macro is defined.
 Preprocessor: Since macros are processed by the preprocessor, they are not seen by
the compiler in their macro form. The preprocessor replaces the macro with its
defined text, and the compiler only sees the resulting code after substitution.

Here’s an example demonstrating both types of macros and their use:

cpp
Copy code
#include <iostream>

#define PI 3.14159 // Object-like macro


#define SQUARE(x) ((x) * (x)) // Function-like macro

int main() {
double radius = 5.0;
std::cout << "Area of the circle: " << PI * SQUARE(radius) <<
std::endl;
return 0;
}

In this example:

 PI is replaced with 3.14159.


 SQUARE(radius) is replaced with ((radius) * (radius)).

The use of macros should be approached with caution in modern C++ programming due to
potential pitfalls with debugging, type safety, and readability. In many cases, inline functions
or constants (const or constexpr) are preferred over macros for better safety and clarity.

The process of building a C++ program with multiple files involves several steps:
preprocessing, compilation, and linking. Here’s a detailed explanation of each step:

1. Preprocessing

The preprocessing step handles all the preprocessor directives, which are lines in your code
that start with the # symbol. The main tasks performed during preprocessing include:

 Macro Expansion: This replaces defined macros with their corresponding values or
code snippets.
 File Inclusion: The #include directive includes the content of a specified file,
usually a header file, directly into the source file. This is essential for separating
declarations (.h or .hpp files) from definitions (.cpp files).
 Conditional Compilation: Directives like #ifdef, #ifndef, #if, #else, #elif, and
#endif control the compilation of parts of the code based on conditions.
 Removing Comments: The preprocessor strips out all comments from the code, as
these are not needed for the actual compilation process.

The result of preprocessing is an expanded source file without any preprocessor directives.

2. Compilation
After preprocessing, the next step is compilation. This phase converts the preprocessed code
(which is still in human-readable C++ form) into machine code, but only for individual
source files. The compiler performs several tasks here:

 Syntax Checking: The compiler checks for syntax errors in the source code. If there
are any syntax errors, the compilation process stops, and the compiler outputs an error
message.
 Semantic Analysis: The compiler also checks for semantic errors, like using a
variable that hasn’t been declared.
 Intermediate Code Generation: The compiler translates the source code into an
intermediate code (like assembly language).
 Optimization: Depending on the compiler settings, optimizations can be applied to
make the code run faster or use less memory.
 Machine Code Generation: The intermediate code is then converted into machine
code (binary code), producing an object file (usually with a .o or .obj extension).

3. Linking

Linking is the final step in creating an executable program from multiple object files. The
linker takes all the compiled object files and combines them into a single executable file. This
process involves:

 Resolving Symbol References: Object files may reference symbols (like variables or
functions) that are defined in other object files or libraries. The linker matches these
symbols with their definitions, ensuring that all references are properly resolved.
 Combining Object Files: The linker combines the machine code from all the object
files into a single executable or library. If there are any missing symbols (e.g., calling
a function that wasn’t defined in any of the object files or linked libraries), the linker
will throw an error.
 Address Binding: The linker assigns final memory addresses to code and data in the
executable, deciding where everything will reside in memory.

Putting It All Together

For a C++ program with multiple files, the process looks something like this:

1. Preprocessing: Each .cpp file is preprocessed independently.


2. Compilation: Each preprocessed file is compiled into an object file.
3. Linking: All object files (and possibly external libraries) are linked together to
produce the final executable.

Example

Let's say you have a simple program with two files: main.cpp and utils.cpp, and a header
file utils.h.

1. Preprocessing:
o main.cpp and utils.cpp are preprocessed, expanding any macros and
including header files like utils.h.
2. Compilation:
o main.cpp is compiled to main.o.
o utils.cpp is compiled to utils.o.
3. Linking:
o main.o and utils.o are linked together to create the final executable (e.g.,
program.exe on Windows or program on Linux).

Understanding these steps is crucial for working with larger projects where source code is
split across multiple files for modularity and reuse.

An object file is a file produced by a compiler after it processes a source code file. It contains
machine code, but it is not yet a complete executable program. Object files are an
intermediate step between source code and the final executable.

Key Characteristics of an Object File

1. Machine Code: Object files contain machine code generated by the compiler from
your source code. This machine code is specific to the target CPU architecture and
operating system but not yet complete for execution.
2. Symbol Table: Object files include a symbol table, which lists all the symbols (such
as function and variable names) defined or used in the source code. Some symbols are
defined within the object file, while others are referenced but not defined (like
external functions or variables from other files or libraries).
3. Relocation Information: Since object files are not yet linked, they often contain
references to addresses that are not yet final. The relocation information helps the
linker adjust addresses when combining multiple object files into a single executable,
ensuring all references are correct.
4. Sections: Object files are typically divided into several sections:
o .text: This section contains the actual compiled machine code for functions
and instructions.
o .data: This section contains initialized global and static variables.
o .bss: This section contains uninitialized global and static variables (variables
that are zero-initialized by default).
o .rodata: This section holds read-only data, such as string literals and constant
values.
5. Not Executable: By itself, an object file cannot be executed. It lacks the necessary
startup code and linkages between all parts of a program. It's a piece of a larger puzzle
that the linker later completes.

How Object Files Are Used

Object files serve as building blocks for creating the final executable program. Here’s how
they fit into the compilation process:

1. Compiling Source Code: Each source code file (.cpp or .c) is compiled into its own
object file (.o or .obj depending on the operating system).
2. Linking: The linker takes all object files generated from the different source files and
combines them into a single executable or library. During this process, the linker:
o Resolves references between object files (e.g., functions or variables declared
in one file and used in another).
o Resolves references to libraries and standard library functions.
o Adjusts addresses based on the final layout of the executable in memory.

Example

Imagine a program split into two source files: main.cpp and utils.cpp.

 main.cpp might look like:

cpp
Copy code
#include "utils.h"

int main() {
printHello();
return 0;
}

 utils.cpp might look like:

cpp
Copy code
#include <iostream>

void printHello() {
std::cout << "Hello, world!" << std::endl;
}

When compiled:

 main.cpp is compiled to main.o (an object file).


 utils.cpp is compiled to utils.o.

Neither main.o nor utils.o is executable on its own. The linker combines these two object
files, resolving the reference to printHello in main.o with its definition in utils.o, and
produces the final executable.

Sure! Let's break down the #include <iostream> directive in C++ by explaining each
component:

1. # (Hash Symbol)

 Preprocessor Directive: The # symbol indicates that the line is a preprocessor


directive. Preprocessor directives are instructions that are executed by the
preprocessor before the actual compilation of the code begins.
 Role: They are used to include header files, define macros, and perform conditional
compilation, among other tasks.
2. include

 Include Directive: The include keyword tells the preprocessor to include the
contents of a specified file into the source code at the point where the directive
appears.
 Functionality: It's essentially a way to copy the contents of one file (usually header
files containing declarations) into another, allowing you to use the functions and
classes defined in that file.

3. <iostream>

 Header File: iostream is a standard header file in C++ that stands for Input/Output
Stream.
 Purpose: It contains definitions for objects like std::cin, std::cout, std::cerr,
and std::clog, which are used for input and output operations.
 Angle Brackets < >: The use of angle brackets indicates that the file is a system or
standard library header file. If you were including your own header file, you would
use double quotes, like #include "myheader.h".

Putting It All Together:

 #include <iostream> tells the preprocessor to include the standard input/output


stream library into your program.
 This inclusion allows you to use standard I/O objects and functions provided by the
C++ Standard Library.

Example Usage:

cpp
Copy code
#include <iostream>

int main() {
std::cout << "Hello, World!" << std::endl; // Uses std::cout from
<iostream>
return 0;
}

 In this example, std::cout and std::endl are defined in the iostream header file,
enabling console output.

Summary:

 #: Indicates a preprocessor directive.


 include: Tells the preprocessor to include a file's contents.
 <iostream>: Specifies the standard header file for input/output stream oper
Class templates in C++ allow you to create generic classes that can operate with any data
type. This is especially useful when you want to write a class that can handle different data
types (such as int, float, double, or even user-defined types) without duplicating code.

By using class templates, you define a blueprint for the class with a placeholder for the data
type, which is then replaced when the class is instantiated.

Syntax:
cpp
Copy code
template <typename T> // or use 'class T'
class ClassName {
T data; // Use 'T' as a placeholder for the type
public:
ClassName(T d) : data(d) {} // Constructor
T getData() { return data; } // Method using 'T'
};

Example:
cpp
Copy code
#include <iostream>
using namespace std;

template <typename T>


class Box {
T value; // Data of type T
public:
Box(T val) : value(val) {} // Constructor
T getValue() { return value; } // Getter function
};

int main() {
Box<int> intBox(123); // Box holding an integer
Box<double> doubleBox(45.67); // Box holding a double

cout << "intBox contains: " << intBox.getValue() << endl;


cout << "doubleBox contains: " << doubleBox.getValue() << endl;

return 0;
}

Output:
sql
Copy code
intBox contains: 123
doubleBox contains: 45.67

Key Points:

1. Template Keyword: The template <typename T> or template <class T> at the
beginning defines a template. Here, T is a placeholder for the actual data type that will
be passed when an object of the class is created.
2. Generic Data Members: Inside the class, you can declare variables of type T or
methods that use T. In the example above, value is a variable of type T.
3. Instantiation: When you create an object of the template class, you specify the data
type. For example, Box<int> creates a Box that holds an integer, and Box<double>
creates a Box that holds a double.
4. Reusability: The same class template can handle different types, making your code
more flexible and reusable.

Example with Multiple Template Parameters:

You can also use multiple template parameters:

cpp
Copy code
template <typename T1, typename T2>
class Pair {
T1 first;
T2 second;
public:
Pair(T1 f, T2 s) : first(f), second(s) {}
void display() {
cout << "First: " << first << ", Second: " << second << endl;
}
};

int main() {
Pair<int, double> p(1, 2.5);
p.display();
return 0;
}

Output:
sql
Copy code
First: 1, Second: 2.5

Class Template Specialization:


You can create a specialized version of the template for certain types if needed. This is
known as template specialization.

cpp
Copy code
template <typename T>
class MyClass {
public:
void display() { cout << "Generic template" << endl; }
};

// Specialization for int type


template <>
class MyClass<int> {
public:
void display() { cout << "Specialized template for int" << endl; }
};

Use Cases of Class Templates:

 Containers: Classes like std::vector, std::list, and std::stack are all


implemented as class templates.
 Generic Data Structures: You can create data structures like stacks, queues, linked
lists, or trees that work with any data type.

Class templates in C++ are a powerful feature for writing generic and reusable code.

The STL (Standard Template Library) is a powerful part of the C++ Standard Library that
provides a set of common data structures and algorithms. It allows developers to work with
collections of data using templates, offering flexibility and efficiency. STL helps in managing
collections such as arrays, lists, stacks, and queues, while also providing algorithms for
sorting, searching, and manipulating these data structures.

Three Main Components of STL:

1. Containers:
o These are used to store data. STL provides several types of containers,
including:
 Sequence Containers (e.g., vector, deque, list)
 Associative Containers (e.g., set, map, multimap)
 Unordered Containers (e.g., unordered_set, unordered_map)
 Container Adapters (e.g., stack, queue, priority_queue)
2. Algorithms:
o STL offers a rich set of algorithms for performing operations on the data
stored in containers. Examples include sorting (sort), searching (find), and
transforming data (transform). These algorithms work seamlessly with the
iterators provided by the containers.
3. Iterators:
o Iterators are objects that point to elements inside containers. They act like
pointers and provide a way to traverse elements within a container. STL
iterators come in different types, such as:
 Input Iterators
 Output Iterators
 Forward Iterators
 Bidirectional Iterators
 Random Access Iterators

Together, these three components make STL a flexible and powerful tool for handling data
and performing operations efficiently in C++.

In C++, std::array, std::vector, and normal arrays (like int x[]) are all used to store
collections of elements, but they have distinct characteristics in terms of memory
management, flexibility, and safety. Here's a comparison:

1. Normal Array (C-style array)

Example:

cpp
Copy code
int x[] = {1, 2, 3};

 Size: The size of a normal array is fixed and cannot be changed after its declaration.
 Memory Management: Normal arrays are stored contiguously in memory, and their
memory is either allocated on the stack (for automatic storage) or the heap (if
dynamically allocated).
 Bounds Checking: There is no bounds checking. Accessing out-of-bounds elements
can lead to undefined behavior.
 Performance: They have minimal overhead and can be slightly faster than other
containers, but the lack of safety features like bounds checking can be problematic.
 Type: Arrays decay to pointers when passed to functions, losing information about
their size.

2. std::array (Fixed-size array)

Example:

cpp
Copy code
#include <array>
std::array<int, 3> arr = {1, 2, 3};

 Size: The size is fixed at compile-time and must be provided as a template parameter
(e.g., std::array<int, 3>). It cannot change at runtime.
 Memory Management: It is stored contiguously in memory, similar to a C-style
array, but encapsulated in a safer and more feature-rich wrapper.
 Bounds Checking: Provides bounds checking with the .at() method, which throws
an exception if accessed out-of-bounds. Regular access with [] doesn't provide
bounds checking.
 Performance: Comparable to normal arrays in terms of performance.
 Type: Does not decay to a pointer when passed to functions, preserving its size and
type information.
 Additional Features: Provides member functions like .size(), .at(), .front(),
.back(), and works well with STL algorithms.

3. std::vector (Dynamic-size array)

Example:

cpp
Copy code
#include <vector>
std::vector<int> vec = {1, 2, 3};

 Size: A std::vector is dynamic and can grow or shrink in size at runtime using
methods like .push_back() or .resize(). Its size can be modified easily after
initialization.
 Memory Management: Memory is allocated dynamically, and std::vector
manages this allocation, resizing, and freeing when the vector is destroyed. It
allocates more memory than necessary to avoid frequent reallocations.
 Bounds Checking: Provides bounds checking with the .at() method, and [] access
does not provide bounds checking.
 Performance: There is a slight overhead due to dynamic memory management, but
it's generally very efficient. Inserting or deleting elements may cause reallocations,
which can be expensive.
 Type: Does not decay to a pointer when passed to functions, preserving its size and
type information.
 Additional Features: Provides a rich set of member functions like .push_back(),
.resize(), .size(), .capacity(), and supports various operations like insertion,
deletion, and iteration.

Summary of Differences:

Feature Normal Array (C-style) std::array std::vector


Size Fixed Fixed Dynamic
Memory
Stack/Heap Stack/Heap Dynamic (Heap)
Management
.at() (bounds .at() (bounds
Bounds Checking No
check) check)
Flexibility No No Yes
Overhead Low Low Slight overhead
Decay to Pointer Yes No No
Lost when passed to
Size Information Retained Retained
functions
STL Compatibility Limited Full Full

In general:
 Use normal arrays for simple, fixed-size cases where performance is critical, but be
cautious about safety.
 Use std::array when you need fixed-size arrays but want the additional safety and
STL compatibility.
 Use std::vector when you need dynamic size and more functionality, like resizing
or adding/removing elements.

4o

The terms static and dynamic refer to different aspects of memory management, storage
duration, and behavior in programming, especially in C++. Here's a comparison of static and
dynamic in these contexts:

1. Memory Allocation

 Static Memory Allocation:


o Memory is allocated at compile-time.
o The size of the memory (e.g., array size, variables) must be known at compile-time.
o Once allocated, it cannot be resized or freed manually.
o Variables with static memory allocation persist for the entire program (global/static
variables) or for the scope's duration (automatic variables).
o Memory for static variables and global variables is allocated in the static/global
memory segment, not the stack.

Example:

cpp
Copy code
int arr[10]; // Static array, size fixed at compile-time

 Dynamic Memory Allocation:


o Memory is allocated at runtime.
o The size can be determined while the program is running, and memory can be
resized or released as needed.
o Typically managed using new and delete (or malloc and free in C).
o The programmer is responsible for freeing dynamically allocated memory to prevent
memory leaks.
o Memory for dynamic variables is allocated on the heap.

Example:

cpp
Copy code
int* arr = new int[10]; // Dynamically allocated array
delete[] arr; // Freeing dynamically allocated memory

2. Lifetime and Storage Duration

 Static:
o Static variables (including global variables) have static storage duration.
o They are allocated once and persist for the entire duration of the program.
o Local static variables retain their value between function calls and are initialized
only once.

Example:

cpp
Copy code
void func() {
static int count = 0; // Static local variable
count++; // Retains value across calls
}

 Dynamic:
o Dynamically allocated variables have dynamic storage duration.
o Their lifetime is controlled by the programmer. They remain in memory until
explicitly deallocated using delete or free.
o If not deallocated, dynamically allocated memory can cause memory leaks.

Example:

cpp
Copy code
int* ptr = new int(5); // Dynamically allocated integer
delete ptr; // Freeing dynamically allocated memory

3. Size

 Static:
o The size of statically allocated memory is fixed and known at compile-time.
o It cannot be changed during runtime.

Example:

cpp
Copy code
int arr[5]; // Fixed size array (5 elements)

 Dynamic:
o The size of dynamically allocated memory can be determined and changed at
runtime.
o You can allocate memory based on user input or other runtime conditions, and
resize if necessary.

Example:

cpp
Copy code
int size;
std::cin >> size; // Get size from user input
int* arr = new int[size]; // Allocate array dynamically based on
size

4. Usage
 Static Memory Allocation:
o Used for variables whose size and lifetime are fixed and known ahead of time.
o Ideal for small, fixed-size data structures like small arrays and global or static
variables.

Advantages:

o Fast access due to fixed memory location.


o No need for manual memory management.

Disadvantages:

o Inflexibility due to fixed size and storage.

 Dynamic Memory Allocation:


o Used when the size of the data structure needs to be flexible or known only at
runtime.
o Ideal for scenarios where memory requirements vary, like user input, linked lists,
trees, and other complex data structures.

Advantages:

o Flexibility in allocating memory of varying sizes during runtime.


o Can manage large amounts of memory that exceed the stack size.

Disadvantages:

o Slower access due to memory being allocated on the heap.


o Must be manually freed to avoid memory leaks.
o Can lead to fragmentation of heap memory if not managed well.

5. Examples

 Static Example (Fixed at Compile-time):

cpp
Copy code
int arr[5]; // Static array, fixed size

 Dynamic Example (Determined at Runtime):

cpp
Copy code
int size;
std::cin >> size; // Size determined at runtime
int* arr = new int[size]; // Dynamically allocated array
delete[] arr; // Don't forget to free memory

Summary of Differences:
Feature Static Allocation Dynamic Allocation

Memory Allocation At compile-time At runtime

Lifetime For the entire program (static) Until manually freed

Storage Location Stack (automatic) or static area Heap

Size Fixed Variable (determined at runtime)

Resizing Not possible Can be resized via reallocation

Efficiency Fast, no allocation overhead Slightly slower due to heap management

Memory Management Automatic Manual (requires delete/free)

In essence, static allocation is fixed and efficient but inflexible, while dynamic allocation
provides flexibility at the cost of more complex memory management.

4o

You said:
is c++ static or dynamic language

ChatGPT said:
ChatGPT

C++ is considered a statically-typed language but supports both static and dynamic
memory management.

1. Statically-Typed Language

C++ is a statically-typed language, meaning that:

 Type checking occurs at compile-time. You must declare the type of a variable before you
use it, and the type of the variable cannot change.
 Once a variable is declared with a type (e.g., int, double, std::string), the compiler
enforces that the variable can only store data of that type.

Example:

cpp
Copy code
int x = 10; // Statically typed: x is always an int

Attempting to assign a different type (e.g., x = "hello") will result in a compile-time error.

2. Memory Management: Static and Dynamic

C++ supports both static and dynamic memory management.


 Static memory management refers to compile-time memory allocation (e.g.,
variables declared on the stack or global/static variables).

Example:

cpp
Copy code
int x = 10; // Statically allocated memory (on the stack)

 Dynamic memory management refers to allocating memory at runtime using new,


delete, malloc, or free, and storing variables in the heap.

Example:

cpp
Copy code
int* p = new int(10); // Dynamically allocated memory (on the heap)
delete p; // Memory must be manually freed

Summary:

 Statically-Typed: C++ is statically typed because variable types are determined and enforced
at compile-time.
 Memory Management: C++ supports both static and dynamic memory allocation, providing
flexibility for different memory management needs.

Thus, while C++ is statically-typed, it provides robust support for dynamic memory
management.

In C++, a structure works the same way as a class, except for just two
small differences. The most important of them is hiding
implementation details. A structure will by default not hide its
implementation details from whoever uses it in code, while a class by
default hides all its implementation details and will therefore by default
prevent the programmer from accessing them. The following table
summarizes all of the fundamental differences.

Class
Structure

Members of a structure are public by


Members of a class are private by default.
default.

Member classes/structures of a class are Member classes/structures of a structure are


private by default. public by default.

It is declared using the class keyword. It is declared using the struct keyword.
Class
Structure

It is normally used for data abstraction and


It is normally used for the grouping of data
further inheritance.

In C++, a union is a special data structure that allows storing different data types in the same
memory location. Unlike a struct, where each member has its own memory, all members of
a union share the same memory space. This means that a union can hold only one of its
members at any given time, and the size of the union is determined by the size of its largest
member.

Here’s an example of a union:

cpp
Copy code
#include <iostream>
using namespace std;

union Data {
int i;
float f;
char str[20];
};

int main() {
Data data;

data.i = 10;
cout << "data.i: " << data.i << endl;

data.f = 220.5;
cout << "data.f: " << data.f << endl;

// Since the members share memory, changing one member affects the
others
strcpy(data.str, "C++ Union");
cout << "data.str: " << data.str << endl;

return 0;
}

Key Characteristics of a union:

 Memory Sharing: All members share the same memory space.


 Single Active Member: Only one member can store a value at any time. If you assign
a new value to one member, it will overwrite the previous value, even if it was stored
in a different member.
 Use Case: Useful when you want to save memory and when only one of the union's
members will be used at a time.
Differences from struct:

 In a struct, each member has its own memory location, while in a union, all
members share the same memory space.
 The size of a struct is the sum of the sizes of its members, whereas the size of a
union is the size of its largest member.

int** x = new int*[3]; for(int i = 0; i < 3; i++){ x[i] = new int[4]; for(int j = 0; j < 4; j++){ cin >> x[i][j]; } }

ChatGPT said:
ChatGPT

This C++ code dynamically allocates a 2D array and takes user input for each element of the
array. Here's a breakdown of the code:

Breakdown:

1. int** x = new int*[3];


o This allocates an array of 3 pointers to int. These pointers will each point to a
separate array.

2. for(int i = 0; i < 3; i++){


o A loop runs 3 times to allocate memory for each row of the 2D array.

3. x[i] = new int[4];


o For each iteration of i, this line allocates an array of 4 int values, representing the
columns in the 2D array for that particular row.

4. for(int j = 0; j < 4; j++){ cin >> x[i][j]; }


o Inside the inner loop, it takes input from the user and stores it in the respective
position in the 2D array x[i][j].

Visualization:

 After running this code, you'll have a 3x4 matrix where each element is dynamically
allocated, and the user will input 12 values in total.

Example Input:
Copy code
1 2 3 4
5 6 7 8
9 10 11 12

This will fill the 2D array with the following values:

css
Copy code
x[0] = {1, 2, 3, 4}
x[1] = {5, 6, 7, 8}
x[2] = {9, 10, 11, 12}
Important Note:

Don't forget to free the dynamically allocated memory when you're done using the array to
avoid memory leaks. Here's how you can deallocate it:

cpp
Copy code
for (int i = 0; i < 3; i++) {
delete[] x[i]; // Deallocate memory for each row
}
delete[] x; // Deallocate memory for the array of pointers
4o

You said:
int ** x what is this

ChatGPT said:
ChatGPT

The declaration int **x in C++ is a pointer to a pointer to an integer, often used to represent
a dynamically allocated 2D array.

What it means:

 int *x: This would be a pointer to an integer, meaning x can store the address of an
integer.
 int **x: This is a pointer to a pointer to an integer. In other words, it can store the address
of a pointer to an integer.

This structure is commonly used for dynamic 2D arrays in C++ because a 2D array can be
viewed as an array of arrays.

Example:

In the code you shared earlier:

cpp
Copy code
int **x = new int*[3]; // Step 1: Allocate an array of 3 int pointers

Here, x is a pointer to a pointer to an integer (int **). The line dynamically allocates an
array of 3 pointers (each element of x is of type int *).

How it's used in 2D Arrays:

To dynamically create a 2D array (e.g., 3 rows and 4 columns):

1. You first allocate memory for an array of pointers to integers (int*[3]).


2. For each row, you allocate memory for an array of integers (int[4]).

Visualization:
 x is a pointer to an array of 3 pointers (int*[3]).
 Each element of x (i.e., x[i]) is a pointer to an array of integers, such as int[4].

So, the data structure can be visualized like this:

arduino
Copy code
x --> [ ptr1 ] --> [ int int int int ]
[ ptr2 ] --> [ int int int int ]
[ ptr3 ] --> [ int int int int ]

Each ptr1, ptr2, and ptr3 holds the address of the dynamically allocated array of integers.

Usage:

This structure allows you to create and manage a 2D array dynamically, where both the
number of rows and columns can be specified at runtime, as opposed to a fixed-size array.

C++ does not allow to pass an entire array as an argument to a function.


However, You can pass a pointer to an array by specifying the array's
name without an index. There are three ways to pass a 2D array to a
function −

Specify the size of columns of 2D array

void processArr(int a[][10]) {


// Do something
}
Pass array containing pointers

void processArr(int *a[10]) {


// Do Something
}

// When callingint *array[10];


for(int i = 0; i < 10; i++)
array[i] = new int[10];
processArr(array);
Pass a pointer to a pointer

void processArr(int **a) {


// Do Something
}
// When calling:
int **array;
array = new int *[10];
for(int i = 0; i <10; i++)
array[i] = new int[10];
processArr(array);
EXAMPLE -

C++
#include<iostream>
using namespace std;

void processArr(int a[][2]) {


cout << "element at index 1,1 is " << a[1][1];
}
int main() {
int arr[2][2];
arr[0][0] = 0;
arr[0][1] = 1;
arr[1][0] = 2;
arr[1][1] = 3;

processArr(arr);
return 0;
}

Output
element at index 1,1 is 3

C++ does not allow you to pass an entire array directly as an argument to a function by
value. When you pass an array to a function, what is actually passed is a pointer to the first
element of the array, not the entire array itself. This is due to the fact that arrays in C++ decay
into pointers when passed to functions.

Explanation:

If you declare an array like this:

cpp
Copy code
int arr[5];

And try to pass it to a function like this:

cpp
Copy code
void myFunction(int arr[]);

myFunction(arr);

What is actually passed to myFunction is a pointer to the first element of arr (not the entire
array), so arr inside the function is treated as int*.

Example:

Here’s how you typically pass an array to a function:


1. Passing the Array (Decayed to a Pointer)
cpp
Copy code
#include <iostream>
using namespace std;

void printArray(int arr[], int size) { // 'arr' is treated as a pointer


for (int i = 0; i < size; i++) {
cout << arr[i] << " "; // Accessing array elements via pointer
}
cout << endl;
}

int main() {
int arr[5] = {1, 2, 3, 4, 5};
printArray(arr, 5); // Passing the array and its size
return 0;
}
2. Passing the Array Using a Pointer

The function can be defined to explicitly take a pointer:

cpp
Copy code
void printArray(int* arr, int size) {
for (int i = 0; i < size; i++) {
cout << arr[i] << " ";
}
cout << endl;
}

Both approaches (using int arr[] or int* arr) are essentially the same in C++ because the
array decays into a pointer when passed to the function.

Important Note:

 Size Information: When passing an array, the size information is not passed along with it.
You must pass the size of the array as a separate argument (like int size in the example).
 Multidimensional Arrays: For multidimensional arrays, you need to pass the sizes of all but
the first dimension.

Alternative: Using std::array or std::vector

If you want to pass an entire array without it decaying into a pointer (i.e., if you want to
preserve size information and pass it by value), you can use std::array or std::vector
from the C++ Standard Library:

 std::array for fixed-size arrays.


 std::vector for dynamic arrays.

Example with std::array:

cpp
Copy code
#include <iostream>
#include <array>

void printArray(std::array<int, 5> arr) {


for (int i = 0; i < arr.size(); i++) {
std::cout << arr[i] << " ";
}
std::cout << std::endl;
}

int main() {
std::array<int, 5> arr = {1, 2, 3, 4, 5};
printArray(arr); // Pass by value
return 0;
}

Example with std::vector:

cpp
Copy code
#include <iostream>
#include <vector>

void printVector(std::vector<int> vec) {


for (int i = 0; i < vec.size(); i++) {
std::cout << vec[i] << " ";
}
std::cout << std::endl;
}

int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
printVector(vec); // Pass by value
return 0;
}

Summary:

 Arrays decay into pointers when passed to functions, so the array's size is not passed.
 If you need to pass the array and its size, you should pass the size separately.
 Use std::array or std::vector if you want to pass an entire array without losing size
information.

4o

Code Explanation:
cpp
Copy code
#include<iostream>
using namespace std;

void processArr(int a[][2]) { // Function accepts a 2D array with 2


columns
cout << "element at index 1,1 is " << a[1][1]; // Access element at row
1, column 1
}
int main() {
int arr[2][2]; // Declare a 2x2 array
arr[0][0] = 0;
arr[0][1] = 1;
arr[1][0] = 2;
arr[1][1] = 3;

processArr(arr); // Pass the array to the function


return 0;
}

Output:
csharp
Copy code
element at index 1,1 is 3

How it works:

1. Array Declaration in main:


o int arr[2][2]; declares a 2D array with 2 rows and 2 columns.
o Values are assigned manually: arr[0][0] = 0, arr[0][1] = 1, etc.

2. Passing Array to Function:


o When you pass the 2D array arr to the processArr function, the array decays into
a pointer to its first element (i.e., the first row).
o In the function declaration void processArr(int a[][2]), the function
expects an array with exactly 2 columns ([2]).

3. Function Access:
o Inside the function, you can access the elements of the array using normal array
indexing: a[1][1] accesses the element in the second row and second column
(which is 3).

Important Notes:

 Fixed Columns in the Function:


o The number of columns ([2] in this case) must be specified in the function
parameter. C++ needs to know the column size because it helps calculate the correct
memory offsets when accessing the elements in a 2D array.
 Row Size Does Not Have to Be Specified:
o The number of rows (2) doesn’t need to be specified in the function declaration
since it’s inferred from the number of elements and how you access them.

What if the array size changes?

If you have an array with a different number of columns (e.g., int arr[2][3];), you would
need to modify the function signature to reflect the new column size, like this:

cpp
Copy code
void processArr(int a[][3]) { // Array with 3 columns
// Code to process array
}

For dynamically sized arrays, you can use pointers, std::vector, or pass additional
information (e.g., the size of the rows and columns) to handle arrays of arbitrary sizes.

4o

You said:
print all elements

ChatGPT said:
ChatGPT

To print all elements of a 2D array in C++, you can use nested loops to iterate through each
row and column. Below is an updated version of your code that prints all elements of the 2D
array:

Updated Code:
cpp
Copy code
#include<iostream>
using namespace std;

void processArr(int a[][2], int rows) {


for (int i = 0; i < rows; i++) { // Loop through rows
for (int j = 0; j < 2; j++) { // Loop through columns (2 in this
case)
cout << "Element at index [" << i << "][" << j << "] is: " <<
a[i][j] << endl;
}
}
}

int main() {
int arr[2][2]; // Declare a 2x2 array
arr[0][0] = 0;
arr[0][1] = 1;
arr[1][0] = 2;
arr[1][1] = 3;

processArr(arr, 2); // Pass array and number of rows (2 in this case)


return 0;
}

Explanation:

1. Nested Loops: The outer loop iterates over the rows, and the inner loop iterates over the
columns. In this case, the number of columns is fixed at 2.
2. Printing Elements: The cout statement prints the value of each element along with its
index.

Output:
less
Copy code
Element at index [0][0] is: 0
Element at index [0][1] is: 1
Element at index [1][0] is: 2
Element at index [1][1] is: 3

This will print all the elements of the 2D array along with their indices.

Generalization:

If you want to handle arrays of arbitrary size, you can modify the function to accept both the
number of rows and columns:

cpp
Copy code
void processArr(int a[][N], int rows, int cols) { // Where N is a constant
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
cout << "Element at index [" << i << "][" << j << "] is: " <<
a[i][j] << endl;
}
}
}

For dynamically sized arrays where the column size is not fixed, use pointers or
std::vector for a more flexible approach.

4o

The approach for matrix multiplication in C++ is to use nested loops to iterate through the
elements of the matrices and perform the multiplication operations.

Here's an example of how you might implement matrix multiplication in C++:

C++
#include <iostream>
using namespace std;

int main() {
int aRows, aCols, bRows, bCols;
cout << "Enter the number of rows and columns for matrix A: ";
cin >> aRows >> aCols;
cout << "Enter the number of rows and columns for matrix B: ";
cin >> bRows >> bCols;

if (aCols != bRows) {
cout << "Error: The number of columns in matrix A must match the
number of rows in matrix B" << endl;
return 1;
}

int matrixA[aRows][aCols], matrixB[bRows][bCols], result[aRows][bCols];


cout << "Enter the elements of matrix A:" << endl;
for (int i = 0; i < aRows; i++) {
for (int j = 0; j < aCols; j++) {
cin >> matrixA[i][j];
}
}

cout << "Enter the elements of matrix B:" << endl;


for (int i = 0; i < bRows; i++) {
for (int j = 0; j < bCols; j++) {
cin >> matrixB[i][j];
}
}

// Initialize the result matrix with zeroes


for (int i = 0; i < aRows; i++) {
for (int j = 0; j < bCols; j++) {
result[i][j] = 0;
}
}

// Perform matrix multiplication


for (int i = 0; i < aRows; i++) {
for (int j = 0; j < bCols; j++) {
for (int k = 0; k < aCols; k++) {
result[i][j] += matrixA[i][k] * matrixB[k][j];
}
}
}

cout << "The result of matrix multiplication is:" << endl;


for (int i = 0; i < aRows; i++) {
for (int j = 0; j < bCols; j++) {
cout << result[i][j] << " ";
}
cout << endl;
}

return 0;
}

The approach is to iterate through the elements of the matrices and perform the multiplication
operations.

The process begins by creating two matrices A and B and reading the number of rows and
columns of these matrices from the user. Matrix multiplication is only possible if the number
of columns of A equals the number of rows of B. This is checked and if not met, the program
exits with an error message.
After that, the program creates a new matrix C of size (A.rows x B.cols) and initializes it with
zero.

Then, the program uses a nested for loop to perform the matrix multiplication:

1. The outermost loop iterates through the rows of matrix A.


2. The middle loop iterates through the columns of matrix B.
3. The innermost loop iterates through the rows of matrix B and columns of matrix A.
At each iteration of the innermost loop, the program multiplies the element at the current
position of matrix A by the element at the current position of matrix B and adds the result to
the element at the corresponding position in matrix C.

It repeats this for every element of the matrices and produces a new matrix C which is the
product of A and B.

In the end, the result matrix C is displayed on the screen for the user to see.

In summary, the approach for matrix multiplication in C++ is:

1. Verifying the dimensions match for multiplication


2. Creating a new matrix C with a size equal to the product of dimensions A & B
3. Performing the operation using nested loops and updating the result matrix C
4. Print the resulting matrix C
It's important to notice that this approach assumes that all matrices are 2D arrays and works
only with square matrices of the same size.
Mark as Read
Report An Issue

what is polymorphism in c_++ oop


ChatGPT said:
ChatGPT

Polymorphism in C++ is a core concept of Object-Oriented Programming (OOP) that allows


objects of different classes to be treated as objects of a common base class. It enables a single
function, operator, or object to behave differently in different contexts. Polymorphism can be
classified into two types:

1. Compile-time Polymorphism (Static Polymorphism):

 Achieved using function overloading and operator overloading.


 The function to be invoked is determined at compile time.
 Function Overloading: Multiple functions with the same name but different
parameter lists can coexist, and the correct one is chosen based on the arguments
passed.

cpp
Copy code
class Printer {
public:
void print(int i) {
std::cout << "Printing int: " << i << std::endl;
}
void print(double f) {
std::cout << "Printing float: " << f << std::endl;
}
void print(std::string s) {
std::cout << "Printing string: " << s << std::endl;
}
};

 Operator Overloading: Operators like +, -, *, etc., can be overloaded to work with


user-defined data types.

cpp
Copy code
class Complex {
public:
int real, imag;
Complex operator + (const Complex& obj) {
Complex temp;
temp.real = real + obj.real;
temp.imag = imag + obj.imag;
return temp;
}
};

2. Runtime Polymorphism (Dynamic Polymorphism):

 Achieved using inheritance and virtual functions.


 The function to be invoked is determined at runtime, based on the type of the object
that invokes the function, not the type of the pointer/reference that points to the
object.
 Virtual Functions: When a base class declares a method as virtual, derived classes
can override it. At runtime, the correct function (based on the object's actual type) is
called.

cpp
Copy code
class Base {
public:
virtual void display() {
std::cout << "Base class display function" << std::endl;
}
};

class Derived : public Base {


public:
void display() override {
std::cout << "Derived class display function" << std::endl;
}
};

int main() {
Base* basePtr;
Derived d;
basePtr = &d;
basePtr->display(); // Calls Derived class function
return 0;
}

In this example, even though basePtr is of type Base*, it points to an object of type
Derived, so the Derived class's display() method is called due to runtime polymorphism.

Summary:

 Compile-time polymorphism is resolved at compile time using function/operator


overloading.
 Runtime polymorphism is resolved at runtime using virtual functions and inheritance.

4o
You said:
i was taught in a course tha tpolymorphism is a set up we can do in our c++ programs to use a base
pointer to mangae derived objects
ChatGPT said:
ChatGPT

You're absolutely correct! The concept you're referring to is runtime polymorphism in C++,
where a base class pointer (or reference) is used to manage objects of derived classes. This
is typically achieved through the use of virtual functions.

Here's a more detailed breakdown:

Runtime Polymorphism Using Base Class Pointer

In C++, runtime polymorphism allows you to use a pointer or reference to the base class
to call methods that are specific to the derived class objects, even if you're interacting with
them via the base class pointer. This is made possible through virtual functions in the base
class, which are overridden in the derived classes. The actual method that gets called is
determined at runtime based on the type of the object that the pointer or reference is pointing
to.

Example of Runtime Polymorphism in C++


cpp
Copy code
#include <iostream>

// Base class
class Animal {
public:
// Virtual function to enable polymorphism
virtual void sound() {
std::cout << "Animal makes a sound" << std::endl;
}
};
// Derived class
class Dog : public Animal {
public:
// Overriding the sound method
void sound() override {
std::cout << "Dog barks" << std::endl;
}
};

// Another derived class


class Cat : public Animal {
public:
// Overriding the sound method
void sound() override {
std::cout << "Cat meows" << std::endl;
}
};

int main() {
// Base class pointer
Animal* animalPtr;

// Derived class object (Dog)


Dog dog;
animalPtr = &dog; // Base pointer pointing to a Dog object
animalPtr->sound(); // Calls Dog's sound method

// Derived class object (Cat)


Cat cat;
animalPtr = &cat; // Base pointer pointing to a Cat object
animalPtr->sound(); // Calls Cat's sound method

return 0;
}

Output:
Copy code
Dog barks
Cat meows

Key Points:

1. Base class pointer (Animal*) is used to point to objects of derived classes (Dog, Cat).
2. The method sound() is declared as virtual in the base class Animal. This enables
polymorphism, allowing the appropriate version of sound() (from Dog or Cat) to be called,
even when using a base class pointer.
3. The derived classes (Dog and Cat) override the base class method sound() with their own
implementations.
4. At runtime, the correct method is invoked based on the type of the object that the pointer
refers to, not the type of the pointer itself.

Why Use This Approach?


 This approach makes your code flexible and extensible. You can use a single pointer type
(Animal*) to manage different derived objects (Dog, Cat, etc.) without needing to know
the exact type of the object at compile time.
 This is useful in scenarios like factory patterns or when you have collections of
heterogeneous objects that share a common base class.

So, when your course described polymorphism as a setup where a base pointer is used to
manage derived objects, it was referring to this dynamic, runtime polymorphism enabled by
virtual functions!

4o

You said:
this is dynamic binding right can you give example of both static and dynamic binding

ChatGPT said:
ChatGPT

Yes, exactly! What you described is dynamic binding, also known as late binding, where
the method to be invoked is determined at runtime based on the object type, not the pointer
or reference type.

To clarify the concept further, let's look at both static (early) and dynamic (late) binding
with examples.

1. Static Binding (Compile-time binding)

In static binding, the method to be called is resolved at compile time. This occurs in
situations like function overloading or operator overloading, where the compiler knows
exactly which function to call based on the function signature or operator usage.

Example of Static Binding


cpp
Copy code
#include <iostream>

class Printer {
public:
// Function overloading (compile-time binding)
void print(int i) {
std::cout << "Printing integer: " << i << std::endl;
}

void print(double d) {
std::cout << "Printing double: " << d << std::endl;
}

void print(std::string s) {
std::cout << "Printing string: " << s << std::endl;
}
};

int main() {
Printer printer;
// Calls the appropriate function based on the argument type (resolved
at compile time)
printer.print(10); // Calls print(int)
printer.print(3.14); // Calls print(double)
printer.print("Hello!"); // Calls print(string)

return 0;
}

Output:
php
Copy code
Printing integer: 10
Printing double: 3.14
Printing string: Hello!

In this example, the function overloading allows multiple print functions to exist with
different parameter types. The compiler determines which one to call at compile time based
on the arguments passed.

2. Dynamic Binding (Runtime binding)

In dynamic binding, the decision about which function to call is made at runtime. This
happens with virtual functions in polymorphism, where the base class pointer or reference
can invoke derived class methods. The function invoked depends on the actual type of the
object, not the type of the pointer or reference.

Example of Dynamic Binding


cpp
Copy code
#include <iostream>

class Animal {
public:
// Virtual function to enable dynamic binding
virtual void sound() {
std::cout << "Animal makes a sound" << std::endl;
}
};

class Dog : public Animal {


public:
// Overriding the sound method
void sound() override {
std::cout << "Dog barks" << std::endl;
}
};

class Cat : public Animal {


public:
// Overriding the sound method
void sound() override {
std::cout << "Cat meows" << std::endl;
}
};
int main() {
Animal* animalPtr;

Dog dog;
Cat cat;

// Base class pointer pointing to Dog object


animalPtr = &dog;
animalPtr->sound(); // Calls Dog's version of sound (runtime binding)

// Base class pointer pointing to Cat object


animalPtr = &cat;
animalPtr->sound(); // Calls Cat's version of sound (runtime binding)

return 0;
}

Output:
Copy code
Dog barks
Cat meows

In this example:

 The sound() function is marked as virtual in the base class Animal.


 At runtime, the correct version of sound() (from Dog or Cat) is called based on the actual
object type, even though animalPtr is of type Animal*.
 This is dynamic binding or late binding because the function call is resolved at runtime.

Key Differences Between Static and Dynamic Binding:

1. Static Binding (Compile-time Binding):


o Happens at compile time.
o Examples: Function overloading, operator overloading, or non-virtual methods.
o The function to be called is determined based on the function signature and
arguments provided.

2. Dynamic Binding (Runtime Binding):


o Happens at runtime.
o Requires the use of virtual functions in a base class.
o The actual function to be called is determined based on the object type (not the
pointer/reference type), and is resolved at runtime.

Summary:

 Static binding is used in cases where the compiler can determine at compile time which
function to call.
 Dynamic binding is used in scenarios where polymorphism is needed, and the function call is
determined at runtime based on the actual object type, typically achieved using virtual
functions.

4o
You said:
in earlier case if we dont make the method virtual and do the same process what happens

ChatGPT said:
ChatGPT

If you don't mark the method as virtual in the base class and attempt the same process,
static binding (also known as early binding) will occur. This means that the method to be
called will be determined at compile time, based on the type of the pointer or reference,
rather than the actual object that the pointer or reference is pointing to.

In simpler terms, without the virtual keyword, the base class method will be called, even if
the pointer is pointing to a derived class object.

Example Without virtual Keyword


cpp
Copy code
#include <iostream>

class Animal {
public:
// No 'virtual' keyword
void sound() {
std::cout << "Animal makes a sound" << std::endl;
}
};

class Dog : public Animal {


public:
// Overriding the sound method, but no dynamic binding will occur
void sound() {
std::cout << "Dog barks" << std::endl;
}
};

class Cat : public Animal {


public:
// Overriding the sound method, but no dynamic binding will occur
void sound() {
std::cout << "Cat meows" << std::endl;
}
};

int main() {
Animal* animalPtr;

Dog dog;
Cat cat;

// Base class pointer pointing to Dog object


animalPtr = &dog;
animalPtr->sound(); // Calls Animal's sound() due to static binding

// Base class pointer pointing to Cat object


animalPtr = &cat;
animalPtr->sound(); // Calls Animal's sound() due to static binding
return 0;
}

Output:
css
Copy code
Animal makes a sound
Animal makes a sound

What Happened:

 Since the sound() method in the base class Animal is not marked as virtual, the
method call is statically bound at compile time.
 When you invoke animalPtr->sound(), the type of the pointer (Animal*) is used to
determine which method to call, not the actual object (Dog or Cat) that animalPtr is
pointing to.
 Therefore, the base class (Animal) method is called in both cases, and you don't get the
derived class (Dog or Cat) method being invoked.

Key Takeaways:

 Without the virtual keyword, static binding occurs. The method to be called is resolved
based on the type of the pointer or reference, rather than the actual type of the object it
points to.
 The virtual keyword is necessary to enable dynamic binding or runtime polymorphism,
allowing the program to call the correct overridden method in the derived class.

In summary, without virtual, the derived class methods won't be called, and you'll always
get the base class method, regardless of which derived object the pointer is pointing to.

4o

You said:
Objects of different classes can be treated as objects of a common superclass how this statement
holds true for polymorphism in context to discussion we had.

ChatGPT said:
ChatGPT

This statement is central to polymorphism in object-oriented programming (OOP), and it


aligns perfectly with our earlier discussion about dynamic binding. Let's break down what it
means and how it ties into polymorphism in C++.

Key Concepts:

1. Inheritance: Inheritance allows you to create a new class (derived class) based on an
existing class (base class or superclass). The derived class inherits the properties and
behaviors (methods) of the base class.
2. Polymorphism: Polymorphism allows objects of different derived classes to be
treated as if they are objects of a common superclass. This means that you can write
code that works with references or pointers to the base class, while the actual object
may belong to any class that derives from the base class.

How It Works:

When you have a class hierarchy, such as:

 A base class (or superclass): Animal


 Derived classes: Dog and Cat

You can treat objects of the derived classes (Dog and Cat) as objects of the base class
(Animal) due to inheritance. This becomes particularly useful in the context of
polymorphism because it allows you to write flexible and reusable code.

In C++, this is achieved through the use of base class pointers or references to handle
objects of the derived class, and virtual functions to allow the appropriate derived class
method to be called at runtime.

Revisiting the Example with Polymorphism:


cpp
Copy code
#include <iostream>

// Base class (superclass)


class Animal {
public:
// Virtual function enables polymorphism
virtual void sound() {
std::cout << "Animal makes a sound" << std::endl;
}
};

// Derived class 1
class Dog : public Animal {
public:
// Overriding the sound method
void sound() override {
std::cout << "Dog barks" << std::endl;
}
};

// Derived class 2
class Cat : public Animal {
public:
// Overriding the sound method
void sound() override {
std::cout << "Cat meows" << std::endl;
}
};

int main() {
// Base class pointer (or reference) can point to objects of derived
classes
Animal* animalPtr;
Dog dog;
Cat cat;

// Treat Dog object as an Animal object


animalPtr = &dog;
animalPtr->sound(); // Calls Dog's sound() at runtime due to
polymorphism

// Treat Cat object as an Animal object


animalPtr = &cat;
animalPtr->sound(); // Calls Cat's sound() at runtime due to
polymorphism

return 0;
}

Output:
Copy code
Dog barks
Cat meows

How the Statement Holds True:

1. Objects of Different Classes: The objects dog (of class Dog) and cat (of class Cat)
are objects of different classes, but both are derived from the common superclass
Animal.
2. Treated as Objects of a Common Superclass: By using a base class pointer
(Animal* animalPtr), we are able to treat both dog and cat as objects of the
common superclass Animal.
3. Polymorphism in Action: Through dynamic binding (enabled by the virtual
function sound() in the base class Animal), the actual object type (whether it's a Dog
or Cat) is determined at runtime. This allows the appropriate sound() method (from
Dog or Cat) to be called, even though we are using a pointer to the base class Animal.

Why This Is Useful:

 Code Reusability: You can write functions, methods, or collections that work with a
base class (Animal), but those same functions can also handle any derived class (Dog,
Cat, etc.) without modification.
 Flexibility: By treating objects of derived classes as objects of their superclass, you
can manage different types of objects through a common interface (the base class).

For instance, you could have a function that takes an Animal* argument, and you could pass
a Dog*, Cat*, or any future class derived from Animal to that function without needing to
rewrite the function.

cpp
Copy code
void makeAnimalSound(Animal* animal) {
animal->sound(); // Polymorphism at work, calls the correct sound()
method
}
int main() {
Dog dog;
Cat cat;

makeAnimalSound(&dog); // Treat Dog as Animal


makeAnimalSound(&cat); // Treat Cat as Animal
}

Output:
Copy code
Dog barks
Cat meows

Conclusion:

The statement "Objects of different classes can be treated as objects of a common


superclass" is a key principle of polymorphism. It allows you to write general-purpose code
that can handle objects from a class hierarchy (like Dog and Cat being treated as Animal),
while still being able to invoke the specific behavior of the derived classes at runtime
through dynamic binding. This is a powerful feature in C++ and OOP in general, enabling
more flexible, extensible, and reusable code.

4o

ChatGPT can make mistakes. Check important info.

Classes and Objects are basic concepts of Object Oriented Programming


which revolve around real-life entities.

Class

A class is a user-defined blueprint or prototype from which real-world


objects are created. It represents the set of properties or methods that
are common to all objects of one type.
We can call class as a collection of objects, which is a logical entity and
does not take space in the memory.
Example : Dog Class can be represented as shown in the diagram below.

It is a basic unit of Object Oriented Programming and represents the real-


life entities. A typical Java program creates many objects, which as you
know, interact by invoking methods.
Objects having memory addresses and take up some space. They can
interact with each other without knowing the data and code.
An object consists of:-

 State : It is represented by the attributes of an object. It also


reflects the properties of an object.
 Behavior : It is represented by the methods of an object. It also
reflects the response of an object with other objects.
 Identity : It gives a unique name to an object and enables one
object to interact with other objects.

The capability of a class to derive properties and characteristics from


another class is called Inheritance. Inheritance is one of the most
important feature of Object Oriented Programming.

 Sub Class: The class that inherits properties from another class is
called Sub class or Derived Class.
 Super Class: The class whose properties are inherited by sub class
is called Base Class or Super class.
 Reusability: Inheritance supports the concept of “reusability”, i.e.
when we want to create a new class and there is already a class
that includes some of the code that we want, we can derive our new
class from the existing class. By doing this, we are reusing the fields
and methods of the existing class.

Example : Dog, Cat, and Cow can the be derived classes of Animal base
class.

The word polymorphism means having many forms. In simple words, we can
define polymorphism as the ability of a message to be displayed in more than
one form.
A real-life example of polymorphism is that a person at the same time can have
different characteristics. Like a man at the same time can be a father, a
husband, and an employee. So the same person posses different behavior in
different situations. This is called polymorphism.
Example: Suppose we have to write a function to add some integers, some
times there are 2 integers and some times there are 3 integers. We can write the
Addition Method with the same name having different parameters, the
concerned method will be called according to parameters.

Data Abstraction is the property by virtue of which only the essential


details are displayed to the user. The trivial or the non-essentials units are
not displayed to the user. Ex: A car is viewed as a car rather than its
individual components.

Data Abstraction may also be defined as the process of identifying only


the required characteristics of an object and ignoring the irrelevant
details. The properties and behaviors of an object differentiate it from
other objects of similar type and also help in classifying/grouping the
objects.

Consider a real-life example of a man driving a car. The man only knows
that pressing the accelerators will increase the speed of the car or
applying the brakes will stop the car, but he does not know about how on
pressing the accelerator the speed is actually increasing, he does not
know about the inner mechanism of the car or the implementation of
accelerator, brakes, etc in the car. This is what abstraction is.

Advantages of Abstraction

 It reduces the complexity of viewing things.


 Avoids code duplication and increases reusability.
 Helps to increase the security of an application or program as only
the important details are provided to the user.

Encapsulation

Encapsulation is defined as the wrapping up of data under a single unit. It


is the mechanism that binds together the code and the data it
manipulates. Another way to think about encapsulation is that it is a
protective shield that prevents the data from being accessed by the code
outside this shield.

 Technically in encapsulation, the variables or data of a class are


hidden from any other class and can be accessed only through any
member function of own class in which they are declared.
 As in encapsulation, the data in a class is hidden from the other
classes, so it is also known as data-hiding.
 Encapsulation can be achieved by declaring all the variables in the
class as private and writing public methods in the class to set and
get the values of the variables.

Advantages of Encapsulation:

 Data Hiding: The user will have no idea about the inner
implementation of the class. It will not be visible to the user how the
class is storing values in the variables. He only knows that we are
passing the values to a setter method and that the variables are
getting initialized with that value.
 Increased Flexibility: We can make the variables of the class as
read-only or write-only, depending on our requirements. If we wish
to make the variables as read-only then we have to omit the setter
methods such as setName(), setAge() etc. or if we wish to make the
variables as write-only then we have to omit the get methods such
as getName(), getAge(), etc.
 Reusability: Encapsulation also improves the re-usability and
makes the code easy to change with new requirements.
 Testing code is easy: Encapsulated code is easy to test for unit
testing.

Encapsulation vs Data Abstraction

 Encapsulation is data hiding(information hiding) while Abstraction is


detail hiding(implementation hiding).
 While encapsulation groups together the data and the methods that
act upon the data, data abstraction deals with exposing the
interface to the user and hiding the details of the implementation.

Abstraction and encapsulation are both fundamental concepts in object-oriented


programming, but they serve different purposes and address different aspects of a program’s
structure. Here's a detailed breakdown of the differences:

1. Conceptual Focus

 Abstraction: Abstraction is the concept of hiding the complexities of an


implementation and exposing only the necessary functionality to the user. It focuses
on what an object does rather than how it performs the task. Abstraction simplifies
interaction by emphasizing relevant information and ignoring the underlying details.
o Example: When you use a smartphone, you interact with its features like
calling, texting, or browsing the internet. You don’t need to understand how
the phone’s hardware or software is processing these functions.
 Encapsulation: Encapsulation, on the other hand, deals with bundling data (variables)
and methods (functions) that manipulate that data into a single unit, usually a class. It
restricts direct access to some of the object’s components to protect the integrity of
the data. Encapsulation ensures that the internal representation of an object is hidden
from the outside and only accessed via publicly exposed methods.
o Example: A TV remote’s functionality is encapsulated. The remote buttons
(methods) allow users to perform actions like changing the channel, but the
internal workings—how it transmits signals to the TV—are hidden from the
user.

2. Purpose

 Abstraction: The purpose of abstraction is to reduce complexity by providing a


simplified interface and hiding irrelevant details. It is about simplifying the interaction
with a complex system by exposing only the essential functionalities.
o Key Goal: It reduces the cognitive load for the user by focusing on high-level
functionality, without getting into the specifics of how the functionality is
executed.
 Encapsulation: Encapsulation is more concerned with protecting data from
unauthorized access or unintended modification. It safeguards an object’s internal
state and ensures that changes to that state are controlled via specific methods.
o Key Goal: To maintain data integrity and security by controlling access to the
object’s internal variables.

3. Implementation

 Abstraction: Abstraction is achieved through interfaces or abstract classes. It allows


developers to define methods or functions without worrying about the implementation
details. In abstraction, the interface is exposed, while the inner workings are hidden.
o In Code: You can use abstract classes and interfaces in languages like Java or
C++ to implement abstraction. For example, an abstract class Vehicle might
define a method start() without implementing how each specific type of
vehicle (car, truck, bike) should start.

cpp
Copy code
class Vehicle {
public:
virtual void start() = 0; // Pure virtual function
};

class Car : public Vehicle {


public:
void start() override {
// Car's specific start mechanism
}
};

class Bike : public Vehicle {


public:
void start() override {
// Bike's specific start mechanism
}
};

 Encapsulation: Encapsulation is implemented by using access modifiers like


private, protected, and public to restrict or grant access to an object’s attributes
or methods. By marking certain data members as private, the object’s data is hidden
from the outside world and can only be accessed or modified through public getter
and setter methods.
o In Code: Here is an example using a class in C++ to demonstrate
encapsulation:

cpp
Copy code
class Account {
private:
double balance; // Private member cannot be accessed directly

public:
void setBalance(double amount) {
if(amount >= 0) {
balance = amount; // Setting balance through a public
method
}
}

double getBalance() {
return balance; // Accessing balance through a public method
}
};

4. Level of Visibility

 Abstraction: In abstraction, the inner workings of an object are not exposed to the
outside world. Only the essential operations that an object can perform are visible to
the user.
o Analogy: Think of an ATM. As a user, you care about depositing,
withdrawing, or checking your balance. You don't need to know the intricate
details of the bank's internal system or how the ATM communicates with the
bank servers.
 Encapsulation: Encapsulation controls the visibility of the data and how the data can
be accessed or modified. It creates a protective layer around the object, where data
can be manipulated only through predefined methods.
o Analogy: Consider a pill bottle. The medication (data) inside is encapsulated
by the bottle. You can only access it by opening the cap (using methods), and
the bottle ensures that you don’t tamper with the contents unnecessarily.

5. Real-World Examples

 Abstraction:
o In a car, abstraction is represented by how you interact with it—steering,
braking, or accelerating without knowing the mechanical complexities of the
engine, transmission, or braking system.
oSmartphone apps are another example of abstraction. Users interact with the
apps without knowing the complex algorithms or the code running behind the
scenes.
 Encapsulation:
o Medical records: In a hospital’s database, patient information is encapsulated,
with access restricted to authorized personnel. Doctors can view and update
medical records, but unauthorized individuals cannot access this sensitive
information.
o Banking systems: When you perform a transaction, your bank account
balance is encapsulated. You can only modify it through certain predefined
actions, like making deposits or withdrawals, but you cannot directly alter the
account balance by accessing the internal workings of the banking system.

6. Example in Software Development

 Abstraction: Consider an online payment gateway system. Abstraction hides the


complexity of handling payments. The user interacts with a simple interface (choose a
payment method, enter card details, and confirm payment), while the underlying
process involving card validation, encryption, communication with banks, and
transaction processing is hidden from view.
 Encapsulation: In a payment processing system, sensitive data like credit card
numbers and user information is encapsulated. The system only allows access to these
details through secure, encrypted channels, and only authorized functions can
manipulate or retrieve this data. This ensures data security and prevents unauthorized
access.

Summary of Key Differences

Feature Abstraction Encapsulation


Hides complexity and shows only Bundles data and methods, hides
Definition
essential details internal data
Focus Focuses on what an object does Focuses on how data is protected
Achieved through interfaces or Achieved through access modifiers
Implementation
abstract classes (private, public, etc.)
Internal data hidden, accessible via
Visibility Only essential features are visible
methods
Simplifies interaction, reduces Ensures data security and controlled
Objective
complexity access
Real-world
A smartphone’s user interface A pill bottle that encloses medication
analogy

In essence, abstraction and encapsulation are complementary concepts. Abstraction


simplifies how users interact with a system by showing only the relevant parts, while
encapsulation ensures that the system's inner workings are protected and controlled. Both are
essential for designing robust, maintainable, and secure software systems.

#include <bits/stdc++.h>
using namespace std;
class Employee { //Class Declaration
public:
string id, name;
int years; //experience (in years)

Employee(string id, string name, int years) {


this->id = id;
this->name = name;
this->years = years;
}

void work() {
cout << "Employee: " << this->id << " is working\n";
}
};

int main()
{
//Class Instantiation (Direct)
Employee emp("GFG123", "John", 3);

//Class Instantiation (Indirect)


Employee *emp_ptr = new Employee("GFG456", "James", 4);

cout << "Employee ID: " << emp.id << endl;


cout << "Name: " << emp.name << endl;
cout << "Experience (in years): " << emp.years << endl;

emp.work();
cout << endl;

cout << "Employee ID: " << emp_ptr->id << endl;


cout << "Name: " << emp_ptr->name << endl;
cout << "Experience (in years): " << emp_ptr->years << endl;

emp_ptr->work();
return 0;
}

#include <bits/stdc++.h>
using namespace std;

class Employee { //Class Declaration


public:
string id, name;
int years; //experience (in years)

Employee(string id, string name, int years) {


this->id = id;
this->name = name;
this->years = years;
}
//Prototype Declaration
void work();
};

//Outside-class definition
void Employee::work() {
cout << "Employee: " << this->id << " is working\n";
}

int main()
{
//Class Instantiation (Direct)
Employee emp("GFG123","John",3);

emp.work();
return 0;
}

Structs vs Classes in C++


In C++, a structure is the same as a class except for a few differences.
The most important of them is security. A Structure is not secure and
cannot hide its implementation details from the end user while a class is
secure and can hide its programming and designing details. Following are
the points that expound on this difference:

1. Members of a class are private by default and members of a struct


are public by default
2. When deriving a struct from a class/struct, default access-specifier for
a base class/struct is public. And when deriving a class, the default
access specifier is private.

A Constructor is a member function of a class that initializes objects of a


class. In C++, Constructor is automatically called when an object
(instance of the class) is created. It is a special member function of the
class.

How constructors are different from a normal member function?

A constructor differs from member-functions in the following ways:

 Constructor has the same name as the Class itself.


 Constructors don’t have a return type.
 A Constructor is automatically called when an object is created.
 If we do not specify a constructor, C++ compiler generates a default
constructor for us (expects no parameters and has an empty body).
Default Constructor

It is not mandatory for the programmer to write a constructor for each


class. C++ by default provides a default constructors with no parameters,
and no statements for the body. Much like being:
A Constructor is a member function of a class that initializes objects of a
class. In C++, Constructor is automatically called when an object
(instance of the class) is created. It is a special member function of the
class.

Constructor Overloading

We need to first get a grasp of overloading first, which is explained as:


Overloading: Having the same name for a member-function/constructor
as long as the list of arguments is different is called overloading. In such a
case, depending upon the arguments passed, the appropriate overloaded
function is deduced and called. An example of constructor overloading:

CPP
#include <bits/stdc++.h>
using namespace std;

class Employee {
public: // public access-modifier
string id, name;
int years;

Employee()
{
id = "";
name = "";
years = 0;
}

// Overloaded constructor
Employee(string id, string name, int years)
{
this->id = id;
this->name = name;
this->years = years;
}

// Overloaded constructor
Employee(string id, string name)
{
this->id = id;
this->name = name;
years = 0;
}

void getDetails()
{
cout << "ID: " << id << ", Name: " << name
<< ", Experience: " << years << endl;
}
};

int main()
{
// 1st constructor is called
Employee emp1;

// 2nd constructor is called


Employee emp2("GFG123", "John", 4);

// 3rd constructor is called


// where years is 0 (no experience for a fresher)
Employee fresher("GFG456", "James");

emp1.getDetails();
emp2.getDetails();
fresher.getDetails();

return 0;
}

Output:

ID:, Name:, Experience: 0


ID: GFG123, Name: John, Experience: 4
ID: GFG456, Name: James, Experience: 0

Member Initializer List

Member Initialization List is a new syntactic construct introduced in


modern C++, which allows us to write concise initialization code in
constructors. The basic syntax is as:

Constructor(< arguments >) : < mem1(arg1), mem2(arg2), ...., >


{
//additional code to execute after initialization
}
CPP
#include <bits/stdc++.h>
using namespace std;

class Employee {
public: // public access-modifier
string id, name;
int years;

Employee(string id, string name, int years)


: id(id), name(name), years(years)
{
// extra code to run after initialization
}

// does the same as:


// Employee(string id, string name, int years) {
// this->id = id;
// this->name = name;
// this->years = years;

// // extra-code to run after initialization


// }

void getDetails()
{
cout << "ID: " << id << ", Name: " << name
<< ", Experience: " << years << endl;
}
};

int main()
{
Employee emp("GFG123", "John", 4);

emp.getDetails();

return 0;
}

Output:

ID: GFG123, Name: John, Experience: 4


Constructor Chaining (Delegation)

Constructor chaining/delegation is the process of re-using constructors by


others to avoid writing repeated code. This is done by calling one
constructor to set common values by other constructors. As an example:

CPP
#include <bits/stdc++.h>
using namespace std;

class Employee {
public: // public access-modifier
string id, name;
int years;

Employee(string id)
: id(id)
{
}

// uses constructor1 constructor1 call


Employee(string id, string name)
: Employee(id)
{
this->name = name;
}

// uses constructor2 constructor2 call


Employee(string id, string name, int years)
: Employee(id, name)
{
this->years = years;
}

void getDetails()
{
cout << "ID: " << id << ", Name: " << name
<< ", Experience: " << years << endl;
}
};

int main()
{
Employee emp("GFG123", "John", 4);
emp.getDetails();

return 0;
}
Output:

ID: GFG123, Name: John, Experience: 4

Destructors

Destructors like constructors are special members of a class that is


executed once the lifetime of the object expires. It is like the final clean-
up code required before deleting the class instance. Unlike JAVA, C++
doesn't perform automatic garbage collection. Hence, it often becomes
the responsibility of the developer to de-allocate memory (not required
further). A classic example:

CPP
#include <bits/stdc++.h>
using namespace std;

char* p_chr;

class String {
public:
char* s;
int size;

String(char* c)
{
size = strlen(c);
s = new char[size + 1];
p_chr = s; // assign to global variable
strcpy(s, c);
}
};

void func()
{
String str("Hello World");
}

int main()
{
func();
cout << p_chr << endl;
return 0;
}
Output:

Hello World

In the above code, we dynamically create a character array in our


constructor, where we copy the string passed as an argument. Since it is a
dynamically-allocated memory, once, the lifetime of str object expires
(inside the func() call), still the memory is not de-allocated, as in main(),
when we print p_chr, we get the string. Thus, we can see that proper
clean-up of pointer references doesn't occur. Thus, we need destructors
where we would explicitly de-allocate the memory and perform other
clean-up code. Syntax of destructor:

~ Classname { //clean-up code }

The above code with destructors:

CPP
#include <bits/stdc++.h>
using namespace std;

char* p_chr;

class String {
public:
char* s;
int size;

String(char* c)
{
size = strlen(c);
s = new char[size + 1];
p_chr = s;
strcpy(s, c);
}

// Destructor
~String()
{
delete[] s;
}
};

void func()
{
String str("Hello World");
}
int main()
{
func();
cout << p_chr << endl;
return 0;
}

The above code prints nothing because p_chr reference is gone due to
destructor call.

Copy Constructor

A copy constructor is a member function that initializes an object using


another object of the same class. A copy constructor has the following
general function prototype:

Classname (const Classname &object);

Copy constructor, in general, is not required to be defined by the user, as


the compiler automatically provides a default copy constructor. However,
this default copy constructor performs a shallow copy only (i.e. copy
values only). This results in pointer variables pointing the same instances
upon copy. We need to define our own copy constructor only if an object
has pointers or any runtime allocation of the resource like file handle, a
network connection.etc.
As an example:

CPP
#include <bits/stdc++.h>
using namespace std;

class Array {
public:
int n;
int* ref;

Array(int n)
: n(n)
{
ref = new int[n];

for (int i = 0; i < n; i++)


*(ref + i) = i;
}
};

int main()
{
Array arr1(10);

// copy constructor called


// at this point
Array arr2 = arr1;

// changing n-value in 2nd instance


arr2.n = 5;

// changing array-values in 2nd instance


for (int i = 0; i < 10; i++)
*(arr2.ref + i) *= 2;

cout << "n-value of 1st instance: " << arr1.n << endl;
cout << "Array values of 1st instance:\n";
for (int i = 0; i < 10; i++)
cout << *(arr1.ref + i) << " ";
cout << endl;

return 0;
}

Output:

n-value of 1st instance: 10


Array values of 1st instance:
0 2 4 6 8 10 12 14 16 18

In the above code, we find the value of member n for t1 not modified as it
is not a pointer value. Thus, upon copying new instance of n got created
for t2. Any change to n in t2 didn't change t1.n. However, t1.ref is a
pointer. So, upon copy-constructor call, the address value got copied
to t2.ref, and thus, any change at t2.ref (as we here are multiplying by 2),
gets reflected at t1.ref also because both of them are pointing to the
same array. This is an example of a shallow-copy. To fix this, we write our
custom copy-constructor:

CPP
#include <bits/stdc++.h>
using namespace std;

class Array {
public:
int n;
int* ref;

Array(int n)
: n(n)
{
ref = new int[n];

for (int i = 0; i < n; i++)


*(ref + i) = i;
}

// copy-contructor definition
Array(const Array& obj)
: n(obj.n)
{
ref = new int[n];

for (int i = 0; i < n; i++)


*(ref + i) = *(obj.ref + i);
}
};

int main()
{
Array arr1(10);

// copy constructor called


// at this point
Array arr2 = arr1;

// changing n-value in 2nd instance


arr2.n = 5;

// changing array-values in 2nd instance


for (int i = 0; i < 10; i++)
*(arr2.ref + i) *= 2;

cout << "n-value of 1st instance: " << arr1.n << endl;
cout << "Array values of 1st instance:\n";
for (int i = 0; i < 10; i++)
cout << *(arr1.ref + i) << " ";
cout << endl;

return 0;
}

Output:

n-value of 1st instance: 10


Array values of 1st instance:
0 1 2 3 4 5 6 7 8 9

We can see that in our copy-constructor, we re-create a dynamic memory


for the array and then copy the values. This results in a deep-copy.
Meaning changes in arr2 doesn't affect arr1.

To understand 'this' pointer, it is important to know how objects look at functions and data
members of a class.

1. Each object gets its own copy of the data member.


2. All access the same function definition as present in the code segment.

Meaning each object gets its own copy of data members and all objects share a single copy of
member functions.
Then now question is that if only one copy of each member function exists and is used by
multiple objects, how are the proper data members are accessed and updated?
The compiler supplies an implicit pointer along with the names of the functions as 'this'.
The 'this' pointer is passed as a hidden argument to all nonstatic member function calls and is
available as a local variable within the body of all nonstatic functions. 'this' pointer is a
constant pointer that holds the memory address of the current object. 'this' pointer is not
available in static member functions as static member functions can be called without any
object (with class name).
For class X, the type of this pointer is 'X* const'. Also, if a member function of X is declared
as const, then the type of 'this' pointer is 'const X *const'.

Following are the situations where 'this' pointer is used:

When local variable's name is same as member's name

CPP
#include <bits/stdc++.h>
using namespace std;

class Employee {
public:
string id, name;
int years;

//'this' keyword here retrieves the object's


//instance variables: id, name, years hidden
//by their same-name local counterparts
Employee(string id, string name, int years) {
this->id = id;
this->name = name;
this->years = years;
}

//here we don't need to use 'this' keyword


//explicitly as their are no local variables
//with the same name. So, compiler automatically
//deduces it as instance variables
void printDetails() {
cout << "ID: " << id
<< ", Name: " << name
<< ", Experience: " << years;
}
};

int main()
{
Employee emp("GFG123", "John", 4);

emp.printDetails();
return 0;
}

Output:

ID: GFG123, Name: John, Experience: 4

For constructors, initializer list can also be used when parameter name is same as member's
name.

To return reference to the calling object

CPP
/* Reference to the calling object can be returned */
Test& Test::func ()
{
// Some processing
return *this;
}

When a reference to a local object is returned, the returned reference can be used to chain
function calls on a single object.

CPP
#include <bits/stdc++.h>
using namespace std;

class Employee {
private:
string id, name;
int years;

public:
Employee setId(string id) {
this->id = id;
return *this;
}

Employee setName(string name) {


this->name = name;
return *this;
}

Employee setYears(int years) {


this->years = years;
return *this;
}

void printDetails() {
cout << "ID: " << id
<< ", Name: " << name
<< ", Experience: " << years;
}
};

int main()
{
Employee emp;

emp.setId("GFG123").setName("John").setYears(4).printDetails();

return 0;
}

Output:

ID: GFG123, Name: John, Experience: 4

In the above code, each time we call the setter methods, the employee instance we are
referring to is returned using the 'this' pointer. We can thus re-use this instance to chain more
method calls.
Mark as Read
Report An Issue

You might also like