0% found this document useful (0 votes)
9 views126 pages

Opp Summerised

This C++ Revision Guide provides a comprehensive overview of the C++ programming language, covering its key features, advantages, and disadvantages. It includes sections on environment setup, basic syntax, data types, functions, and various programming constructs such as loops and decision-making statements. The guide aims to equip learners with essential knowledge for mastering C++ and preparing for exams.

Uploaded by

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

Opp Summerised

This C++ Revision Guide provides a comprehensive overview of the C++ programming language, covering its key features, advantages, and disadvantages. It includes sections on environment setup, basic syntax, data types, functions, and various programming constructs such as loops and decision-making statements. The guide aims to equip learners with essential knowledge for mastering C++ and preparing for exams.

Uploaded by

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

This guide is structured to cover all the topics in a clear, concise, and professional manner,

ensuring you have a top-tier understanding of C++ for your exams.

C++ Revision Guide (Enhanced)

1. Overview
• What is C++?
o C++ is a high-performance programming language used for developing
software, games, and system applications.
o It supports object-oriented programming (OOP), which organizes code into
reusable objects.
• Key Features:
o Object-Oriented Programming (OOP): Encapsulation, inheritance, and
polymorphism.
o Standard Template Library (STL): Provides pre-built data structures and
algorithms.
o Portability: C++ code can run on multiple platforms (Windows, Mac, Linux).
• Why Learn C++?
o It offers fine-grained control over system resources and memory.
o It is widely used in industries like gaming, finance, and robotics.
o It is fast and efficient, making it ideal for performance-critical applications.

Advantages of C++

1. High Performance:
o Compiled language with direct machine code execution.
o Allows low-level memory manipulation for fine-grained control.
2. Object-Oriented Programming (OOP):
o Supports encapsulation, inheritance, and polymorphism.
o Promotes code reusability and modularity.
3. Rich Standard Library (STL):
o Provides pre-built data structures and algorithms.
o Reduces the need to write code from scratch.
4. Portability:
o Code can run on multiple platforms (Windows, Linux, macOS) with minimal
changes.
5. Memory Management:
o Manual memory management gives developers control over system resources.
Disadvantages of C++
1. Complexity:
o Steep learning curve due to advanced features like pointers and OOP.
o Can be overcomplicated for small projects.
2. Manual Memory Management:
o No garbage collection, leading to potential memory leaks or dangling pointers.
3. Verbose Syntax:
o Requires more code compared to modern languages like Python.
4. Security Vulnerabilities:
o Prone to issues like buffer overflows and pointer misuse.
5. Slow Development Cycle:
o Compilation process can be time-consuming for large projects.
o Not ideal for rapid prototyping.

2. Environment Setup
• Tools Needed:
o Text Editor: VS Code, Notepad++, or Sublime Text.
o Compiler: GCC, Clang, or Visual Studio.
• Online Compiler:
o Use www.compileonline.com to run C++ code without installation.
• Local Setup:
o Windows: Install MinGW or Visual Studio.
o Linux: Use sudo apt-get install g++ to install GCC.
o Mac: Install Xcode from the App Store.

3. Basic Syntax
• Structure of a C++ Program:
#include <iostream> // Include input/output library
using namespace std; // Use the standard namespace

int main() { // Main function where execution begins


cout << "Hello World!"; // Print "Hello World!"
return 0; // Return 0 to indicate successful execution
}

• Explanation:
o #include <iostream>: Allows input/output operations.
o using namespace std;: Lets you use cout and cin without writing std::.
o int main(): The starting point of the program.
o cout << "Hello World!";: Prints text to the console.
o return 0;: Ends the program successfully.

4. Comments in C++
• Single-line Comments:
// This is a single-line comment

• Multi-line Comments:
/* This is a
multi-line comment */

5. Data Types
• Primitive Data Types:
Data Type Description Example
int Integer numbers int age = 25;
float Floating-point numbers float pi = 3.14;
double Double-precision floating-point double salary = 5000.50;
char Single character char grade = 'A';
bool Boolean (true/false) bool isTrue = true;

6. Variable Types
• Variables: Used to store data that can change.
int x = 10; // Declare and initialize a variable
x = 20; // Change the value of x

• Constants: Used to store data that cannot change.


const int PI = 3.14; // Declare a constant
// PI = 3.15; // Error: Cannot change a constant

7. Variable Scope
• Local Variables: Declared inside a function and accessible only within that function.
void myFunction() {
int x = 10; // Local variable
cout << x;
}

• Global Variables: Declared outside all functions and accessible throughout the program.
int x = 10; // Global variable
void myFunction() {
cout << x;
}

8. Constants/Literals
• Integer Literals: Whole numbers (e.g., 10, -5).
• Floating-point Literals: Decimal numbers (e.g., 3.14, -0.5).
• Boolean Literals: true or false.
• Character Literals: Single characters enclosed in single quotes (e.g., 'A', '1').
• String Literals: Sequence of characters enclosed in double quotes (e.g., "Hello").

9. Modifier Types
• Type Modifiers: Change the meaning of the base data type.
o signed: Can store positive and negative values.
o unsigned: Can store only positive values.
o short: Reduces the size of the data type.
o long: Increases the size of the data type.

10. Storage Classes


• auto: Default storage class for local variables.
• register: Suggests the compiler to store the variable in a CPU register.
• static: Retains the value between function calls.
• extern: Declares a global variable or function in another file.
• mutable: Allows a member of an object to be modified by a const function.

11. Operators
• Arithmetic Operators: +, -, *, /, %
• Relational Operators: ==, !=, >, <, >=, <=
• Logical Operators: &&, ||, !
• Bitwise Operators: &, |, ^, ~, <<, >>
• Assignment Operators: =, +=, -=, *=, /=
12. Loop Types
Loops are used to repeat a block of code multiple times until a specific condition is met. C++
provides three types of loops:
• For Loop:
Used when the number of iterations is known in advance.
Combines initialization, condition, and update in a single line
Key Points:
Initialization: Executed once at the start.
Condition: Checked before each iteration. If false, the loop ends.
Update: Executed after each iteration.
for (int i = 0; i < 5; i++) {
cout << i << endl;
}

• While Loop:
Used when the number of iterations is not known in advance.
Continues executing as long as the condition is true.
Key Points:
The condition is checked before each iteration.
If the condition is false initially, the loop never executes.
int i = 0;
while (i < 5) {
cout << i << endl;
i++;
}

• Do-While Loop:
Similar to the while loop, but the condition is checked after the loop body.
Ensures the loop executes at least once.
Key Points:
The loop body executes at least once, even if the condition is false.
Useful for scenarios where the loop must run before checking the condition.
int i = 0;
do {
cout << i << endl;
i++;
} while (i < 5);

13. Decision-Making Statements


• If Statement:
Executes a block of code if a condition is true.
int age = 18;
if (age >= 18) {
cout << "You are an adult.";
}

• if-else Statement
Executes one block of code if the condition is true and another if it is false.
int age = 15;
if (age >= 18) {
cout << "You are an adult.";
} else {
cout << "You are a minor."; // Output: You are a minor.
}
• Switch Statement:
Used to select one of many code blocks to execute based on the value of a variable.
int day = 3;
switch (day) {
case 1: cout << "Monday"; break;
case 2: cout << "Tuesday"; break;
default: cout << "Invalid day";
}

14. Functions

Functions in C++

Functions are blocks of code that perform a specific task. They help in organizing code,
reducing redundancy, and improving readability. Functions can take inputs (parameters),
process them, and return a result.
1. Function Definition

A function definition consists of:

• Return type: The type of value the function returns (e.g., int, void).
• Function name: The name of the function (e.g., add, printMessage).
• Parameters: Inputs to the function (optional).
• Function body: The code that performs the task.

Syntax:
return_type function_name(parameter_list) {
// Function body
return value; // Optional (only if return_type is not void)
}
Example:
int add(int a, int b) {
return a + b;
}

2. Function Declaration (Prototype)

A function declaration tells the compiler about the function's name, return type, and
parameters. It is used when the function is defined after it is called.

Syntax:
return_type function_name(parameter_list);
Example:
int add(int a, int b); // Function declaration

3. Function Call
A function is executed by calling it with the required arguments.

Syntax:
function_name(arguments);
Example:
int result = add(5, 10); // Function call
cout << result; // Output: 15

4. Types of Functions
a) Functions with No Return Type (void)

• These functions do not return any value.


Example:
void printMessage() {
cout << "Hello, World!";
}

int main() {
printMessage(); // Output: Hello, World!
return 0;
}
b) Functions with Return Type

• These functions return a value of a specific type.

Example:
int multiply(int a, int b) {
return a * b;
}

int main() {
int result = multiply(3, 4);
cout << result; // Output: 12
return 0;
}
c) Functions with No Parameters

• These functions do not take any input.

Example:
int getRandomNumber() {
return rand();
}

int main() {
cout << getRandomNumber();
return 0;
}
d) Functions with Default Arguments

• Default values can be assigned to parameters. If the caller does not provide a value, the
default is used.

Example:
int add(int a, int b = 10) {
return a + b;
}

int main() {
cout << add(5); // Output: 15 (uses default b = 10)
cout << add(5, 3); // Output: 8 (overrides default b)
return 0;
}
5. Function Overloading

• Multiple functions can have the same name but different parameters (number or type).

Example:
int add(int a, int b) {
return a + b;
}

double add(double a, double b) {


return a + b;
}

int main() {
cout << add(5, 10) << endl; // Output: 15 (int version)
cout << add(3.5, 2.5) << endl; // Output: 6.0 (double version)
return 0;
}

6. Recursive Functions
• A function that calls itself is called a recursive function.

Example:
int factorial(int n) {
if (n == 0) return 1; // Base case
return n * factorial(n - 1); // Recursive call
}

int main() {
cout << factorial(5); // Output: 120
return 0;
}

7. Inline Functions

• Inline functions are expanded in place (like macros) to reduce the overhead of function
calls.

Syntax:
inline return_type function_name(parameters) {
// Function body
}
Example:
inline int square(int x) {
return x * x;
}

int main() {
cout << square(5); // Output: 25
return 0;
}

8. Pass by Value vs. Pass by Reference


a) Pass by Value

• A copy of the argument is passed to the function.


• Changes made to the parameter do not affect the original argument.

Example:
void increment(int x) {
x++;
}

int main() {
int a = 5;
increment(a);
cout << a; // Output: 5 (unchanged)
return 0;
}
b) Pass by Reference

• The memory address of the argument is passed to the function.


• Changes made to the parameter affect the original argument.

Example:
void increment(int &x) {
x++;
}

int main() {
int a = 5;
increment(a);
cout << a; // Output: 6 (changed)
return 0;
}

9. Lambda Functions (C++11 and later)

• Anonymous functions that can be defined inline.

Syntax:
[capture](parameters) -> return_type {
// Function body
}
Example:
auto add = [](int a, int b) -> int {
return a + b;
};

int main() {
cout << add(5, 10); // Output: 15
return 0;
}

10. Best Practices

1. Use meaningful names for functions.


2. Keep functions short and focused on a single task.
3. Use pass by reference to avoid copying large objects.
4. Use const for parameters that should not be modified.
5. Avoid global variables; prefer passing arguments to functions.

Example: Program to Calculate Area of a Circle


#include <iostream>
using namespace std;

// Function to calculate area of a circle


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

int main() {
double radius;
cout << "Enter radius: ";
cin >> radius;
cout << "Area: " << calculateArea(radius);
return 0;
}

• Functions: Reusable blocks of code.


int add(int a, int b) {
return a + b;
}

int main() {
int result = add(5, 10);
cout << "Sum: " << result;
return 0;
}
15. Numbers
Numbers in C++

In C++, numbers are represented using numeric data types like int, float, double, etc. C++
provides a wide range of mathematical operations and functions to work with numbers.

1. Numeric Data Types


Data Description Size Range
Type
int Integer numbers 4 bytes -2,147,483,648 to 2,147,483,647
float Single-precision floating- 4 bytes ~7 decimal digits of precision
point
double Double-precision floating- 8 bytes ~15 decimal digits of precision
point
long Larger integer numbers 4 or 8 -2,147,483,648 to 2,147,483,647 (or
bytes larger)
short Smaller integer numbers 2 bytes -32,768 to 32,767
unsigned Non-negative integers Same as int 0 to 4,294,967,295

2. Basic Arithmetic Operations


Operator Description Example

+ Addition 5+3 →8

- Subtraction 5-3 →2

* Multiplication 5*3 → 15

/ Division 5/2 →2

% Modulus (remainder) 5%2 →1


Example:
int a = 10, b = 3;
cout << a + b << endl; // Output: 13
cout << a - b << endl; // Output: 7
cout << a * b << endl; // Output: 30
cout << a / b << endl; // Output: 3 (integer division)
cout << a % b << endl; // Output: 1

3. Mathematical Functions
C++ provides a <cmath> library for advanced mathematical operations.

Function Description Example

sqrt(x) Square root of x sqrt(16) → 4.0

pow(x, y) x raised to the power of y pow(2, 3) → 8.0

abs(x) Absolute value of x abs(-5) →5

ceil(x) Rounds x up to the nearest integer ceil(3.2) → 4.0

floor(x) Rounds x down to the nearest integer floor(3.8) → 3.0

round(x) Rounds x to the nearest integer round(3.5) → 4.0

log(x) Natural logarithm of x log(10) → 2.30259

sin(x), cos(x), tan(x) Trigonometric functions (in radians) sin(0) → 0.0

Example:
#include <cmath>
#include <iostream>
using namespace std;

int main() {
cout << sqrt(25) << endl; // Output: 5
cout << pow(2, 3) << endl; // Output: 8
cout << abs(-10) << endl; // Output: 10
cout << ceil(3.2) << endl; // Output: 4
cout << floor(3.8) << endl; // Output: 3
cout << round(3.5) << endl; // Output: 4
return 0;
}
4. Random Numbers

Random numbers can be generated using the <cstdlib> and <ctime> libraries.

Example:
#include <cstdlib>
#include <ctime>
#include <iostream>
using namespace std;

int main() {
srand(time(0)); // Seed the random number generator
int randomNum = rand() % 100; // Random number between 0 and 99
cout << "Random number: " << randomNum;
return 0;
}

5. Number Formatting
C++ provides tools to format numbers, such as setting precision for floating-point numbers.

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

int main() {
double pi = 3.141592653589793;
cout << fixed << setprecision(2); // Set precision to 2 decimal places
cout << "Pi: " << pi << endl; // Output: Pi: 3.14
return 0;
}

6. Type Conversion

Numbers can be converted between different types using type casting.

Example:
int a = 10;
double b = 3.5;

// Implicit conversion
double result1 = a + b; // int + double → double
cout << result1 << endl; // Output: 13.5

// Explicit conversion (type casting)


int result2 = (int)b + a; // double → int
cout << result2 << endl; // Output: 13
7. Handling Large Numbers

For very large numbers, use the long long data type.

Example:
long long bigNum = 1234567890123456789LL;
cout << bigNum << endl; // Output: 1234567890123456789

8. Common Pitfalls

1. Integer Division:
o Dividing two integers results in an integer (truncates the decimal part).
2. int a = 5, b = 2;
3. cout << a / b; // Output: 2 (not 2.5)
4. Overflow:
o Exceeding the range of a data type can cause unexpected behavior.
5. int a = 2147483647; // Maximum value for int
6. cout << a + 1; // Output: -2147483648 (overflow)
7. Precision Loss:
o Floating-point numbers may lose precision due to their limited representation.
8. float f = 0.1f;
9. cout << f; // Output: 0.1 (but may not be exact)

Example: Program to Calculate Compound Interest


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

int main() {
double principal = 1000, rate = 0.05, time = 5;
double amount = principal * pow(1 + rate, time);
cout << "Compound Interest: " << amount - principal;
return 0;
}

• Math Operations:
#include <cmath>
cout << sqrt(16); // Output: 4

• Random Numbers:
#include <cstdlib>
#include <ctime>
srand(time(0));
cout << rand(); // Output: Random number
16. Arrays
• Arrays: Store multiple values of the same type.

Arrays in C++

An array is a collection of elements of the same data type stored in contiguous memory
locations. Arrays are used to store multiple values in a single variable, making it easier to
manage and manipulate data.

1. Declaring an Array
Syntax:
data_type array_name[array_size];
Example:
int numbers[5]; // Declares an array of 5 integers

2. Initializing an Array

Arrays can be initialized at the time of declaration.

Example:
int numbers[5] = {10, 20, 30, 40, 50}; // Initializes an array with 5 values

• If fewer values are provided, the remaining elements are initialized to 0.


• int numbers[5] = {10, 20}; // [10, 20, 0, 0, 0]
• If no size is specified, the array size is determined by the number of values.
• int numbers[] = {10, 20, 30}; // Size is 3

3. Accessing Array Elements

Array elements are accessed using an index (starting from 0).

Syntax:
array_name[index];
Example:
int numbers[5] = {10, 20, 30, 40, 50};
cout << numbers[0]; // Output: 10
cout << numbers[2]; // Output: 30
4. Modifying Array Elements

Array elements can be modified by assigning new values.

Example:
int numbers[5] = {10, 20, 30, 40, 50};
numbers[1] = 25; // Changes the second element to 25
cout << numbers[1]; // Output: 25

5. Iterating Through an Array

Use a loop to access all elements of an array.

Example:
int numbers[5] = {10, 20, 30, 40, 50};
for (int i = 0; i < 5; i++) {
cout << numbers[i] << " "; // Output: 10 20 30 40 50
}

6. Multidimensional Arrays

Arrays can have multiple dimensions (e.g., 2D arrays for matrices).

Syntax:
data_type array_name[row_size][column_size];
Example:
int matrix[2][3] = {
{1, 2, 3},
{4, 5, 6}
};

// Accessing elements
cout << matrix[0][1]; // Output: 2
Iterating Through a 2D Array:
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
cout << matrix[i][j] << " ";
}
cout << endl;
}

7. Passing Arrays to Functions

Arrays can be passed to functions by reference (the array name is a pointer to its first element).
Example:
void printArray(int arr[], int size) {
for (int i = 0; i < size; i++) {
cout << arr[i] << " ";
}
}

int main() {
int numbers[5] = {10, 20, 30, 40, 50};
printArray(numbers, 5); // Output: 10 20 30 40 50
return 0;
}

8. Array Limitations

1. Fixed Size: The size of an array must be known at compile time.


2. No Bounds Checking: Accessing elements outside the array bounds can cause
undefined behavior.
3. Memory Wastage: If the array size is larger than needed, memory is wasted.

9. Dynamic Arrays (Using Pointers)

For arrays with a size determined at runtime, use dynamic memory allocation.

Example:
int* arr = new int[5]; // Dynamically allocate an array of size 5
for (int i = 0; i < 5; i++) {
arr[i] = i + 1;
}
delete[] arr; // Free the allocated memory

10. Standard Library Arrays (C++11 and later)

The <array> header provides a safer and more flexible alternative to traditional arrays.

Example:
#include <array>
#include <iostream>
using namespace std;

int main() {
array<int, 5> numbers = {10, 20, 30, 40, 50};
for (int i = 0; i < numbers.size(); i++) {
cout << numbers[i] << " "; // Output: 10 20 30 40 50
}
return 0;
}
11. Common Array Operations
a) Finding the Largest Element
int numbers[5] = {10, 20, 30, 40, 50};
int max = numbers[0];
for (int i = 1; i < 5; i++) {
if (numbers[i] > max) {
max = numbers[i];
}
}
cout << "Max: " << max; // Output: Max: 50
b) Sum of Array Elements
int numbers[5] = {10, 20, 30, 40, 50};
int sum = 0;
for (int i = 0; i < 5; i++) {
sum += numbers[i];
}
cout << "Sum: " << sum; // Output: Sum: 150
c) Reversing an Array
int numbers[5] = {10, 20, 30, 40, 50};
for (int i = 0; i < 5 / 2; i++) {
swap(numbers[i], numbers[4 - i]);
}
for (int i = 0; i < 5; i++) {
cout << numbers[i] << " "; // Output: 50 40 30 20 10
}

12. Best Practices

1. Use std::array or std::vector for safer and more flexible arrays.


2. Always check array bounds to avoid undefined behavior.
3. Use dynamic arrays when the size is not known at compile time.
4. Prefer range-based for loops for iterating through arrays (C++11 and later).

int numbers[5] = {1, 2, 3, 4, 5};


for (int i = 0; i < 5; i++) {
cout << numbers[i] << endl;
}
17. Strings
Strings in C++

Strings are used to store and manipulate sequences of characters. In C++, strings can be
handled in two ways:

1. C-style strings (character arrays).


2. C++ std::string class (from the <string> library).

1. C-Style Strings

C-style strings are arrays of characters terminated by a null character (\0).

Syntax:
char string_name[size];
Example:
char name[20] = "John"; // Declares a C-style string

2. Initializing C-Style Strings

• Direct Initialization:
• char name[] = "John"; // Automatically adds '\0' at the end
• Character-by-Character Initialization:
• char name[5] = {'J', 'o', 'h', 'n', '\0'};

3. Accessing C-Style Strings

• Use indexing to access individual characters.


• Use pointer arithmetic to traverse the string.

Example:
char name[] = "John";
cout << name[0]; // Output: J
cout << name[2]; // Output: h

4. Common C-Style String Functions

The <cstring> library provides functions to manipulate C-style strings.


Function Description Example
strlen(str) Returns the length of the string strlen("Hello") →5
strcpy(dest, src) Copies src to dest strcpy(dest, "Hello")

strcat(dest, src) Concatenates src to dest strcat(dest, "World")

strcmp(str1, str2) Compares two strings (0 if equal) strcmp("Hello", "Hello") →0

strstr(str, substr) Finds the first occurrence of substr in str strstr("Hello", "lo") → "lo"

Example:
#include <cstring>
#include <iostream>
using namespace std;

int main() {
char str1[20] = "Hello";
char str2[20] = "World";

cout << strlen(str1) << endl; // Output: 5


strcat(str1, str2);
cout << str1 << endl; // Output: HelloWorld
cout << strcmp(str1, str2) << endl; // Output: Non-zero (not equal)
return 0;
}

5. C++ std::string Class

The std::string class (from the <string> library) provides a more convenient and safer way to
handle strings.

Syntax:
#include <string>
using namespace std;

string string_name;
Example:
#include <string>
#include <iostream>
using namespace std;

int main() {
string name = "John";
cout << name; // Output: John
return 0;
}
6. Common std::string Operations
Operation Description Example
str.length() Returns the length of the string name.length() →4

str.size() Same as length() name.size() →4


str.append(str2) Concatenates str2 to str name.append(" Doe") → "John Doe"

str.compare(str2) Compares two strings (0 if equal) name.compare("John") →0

str.substr(pos, len) Extracts a substring name.substr(1, 2) → "oh"


str.find(substr) Finds the first occurrence of substr name.find("oh") →1

str.replace(pos, len, str2) Replaces part of the string with str2 name.replace(1, 2, "ane") → "Jane"

str.erase(pos, len) Removes part of the string name.erase(1, 2) → "Jn"


str.insert(pos, str2) Inserts str2 at position pos name.insert(2, "ane") → "Joanen"

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

int main() {
string name = "John";
cout << name.length() << endl; // Output: 4
name.append(" Doe");
cout << name << endl; // Output: John Doe
cout << name.substr(5, 3) << endl; // Output: Doe
return 0;
}

7. Input and Output with std::string


a) Reading a String from User
string name;
cout << "Enter your name: ";
getline(cin, name); // Reads the entire line
cout << "Hello, " << name << "!";
b) Reading Multiple Words
string firstName, lastName;
cout << "Enter your full name: ";
cin >> firstName >> lastName; // Reads two words
cout << "Hello, " << firstName << " " << lastName << "!";

8. Converting Between C-Style Strings and std::string


a) C-Style String to std::string
char cstr[] = "Hello";
string str = cstr; // Automatically converts
b) std::string to C-Style String
string str = "Hello";
const char* cstr = str.c_str(); // Returns a C-style string

9. Iterating Through a String


a) Using Indexing
string str = "Hello";
for (int i = 0; i < str.length(); i++) {
cout << str[i] << " "; // Output: H e l l o
}
b) Using Range-Based For Loop (C++11 and later)
string str = "Hello";
for (char ch : str) {
cout << ch << " "; // Output: H e l l o
}

10. Common String Manipulations


a) Reversing a String
string str = "Hello";
reverse(str.begin(), str.end());
cout << str; // Output: olleH
b) Converting to Uppercase/Lowercase
#include <algorithm>
#include <cctype>

string str = "Hello";


transform(str.begin(), str.end(), str.begin(), ::toupper);
cout << str; // Output: HELLO

11. Best Practices


1. Prefer std::string over C-style strings for better safety and functionality.
2. Use getline() to read strings with spaces.
3. Avoid hardcoding string sizes when using C-style strings.
4. Use c_str() to convert std::string to C-style strings when necessary.
Example: Program to Check if a String is Palindrome
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;

int main() {
string str = "madam";
string reversed = str;
reverse(reversed.begin(), reversed.end());

if (str == reversed) {
cout << "Palindrome!";
} else {
cout << "Not a palindrome!";
}
return 0;
}

18. Pointers
Pointers in C++

Pointers are variables that store memory addresses of other variables. They are a powerful
feature of C++ that allows for dynamic memory management, efficient array handling, and
passing large structures to functions.

1. Pointer Declaration
Syntax:
data_type* pointer_name;
Example:
int* ptr; // Declares a pointer to an integer

2. Assigning Addresses to Pointers

Use the address-of operator (&) to get the memory address of a variable.

Example:
int num = 10;
int* ptr = &num; // ptr now holds the address of num
3. Accessing Values Using Pointers

Use the dereference operator (*) to access the value stored at the memory address a pointer
points to.

Example:
int num = 10;
int* ptr = &num;
cout << *ptr; // Output: 10 (value at the address stored in ptr)

4. Pointer Arithmetic

Pointers support arithmetic operations like addition, subtraction, increment, and decrement.
These operations are based on the size of the data type the pointer points to.

Example:
int arr[3] = {10, 20, 30};
int* ptr = arr; // Points to the first element of the array

cout << *ptr << endl; // Output: 10


ptr++; // Moves to the next element
cout << *ptr << endl; // Output: 20

5. Pointers and Arrays

Arrays and pointers are closely related. The name of an array is a pointer to its first element.

Example:
int arr[3] = {10, 20, 30};
int* ptr = arr; // ptr points to the first element of arr

cout << *(ptr + 1) << endl; // Output: 20 (second element)


cout << ptr[2] << endl; // Output: 30 (third element)

6. Pointers to Pointers

A pointer can point to another pointer, creating a pointer to a pointer.

Syntax:
data_type** pointer_name;
Example:
int num = 10;
int* ptr = &num;
int** ptr2 = &ptr; // ptr2 points to ptr

cout << **ptr2; // Output: 10 (value of num)


7. Dynamic Memory Allocation

Pointers are used to manage dynamic memory (memory allocated at runtime) using new and
delete.

a) Allocating Memory
int* ptr = new int; // Allocates memory for one integer
*ptr = 10; // Assigns a value to the allocated memory
b) Deallocating Memory
delete ptr; // Frees the allocated memory
c) Allocating Arrays
int* arr = new int[5]; // Allocates memory for an array of 5 integers
arr[0] = 10; // Assigns a value to the first element
delete[] arr; // Frees the allocated array memory

8. Passing Pointers to Functions

Pointers can be passed to functions to modify the original variable or to avoid copying large
data structures.

Example:
void increment(int* ptr) {
(*ptr)++; // Increments the value at the address stored in ptr
}

int main() {
int num = 10;
increment(&num); // Passes the address of num
cout << num; // Output: 11
return 0;
}

9. Pointers and const

• Pointer to a constant: The value pointed to cannot be changed.


• const int* ptr = &num;
• // *ptr = 20; // Error: Cannot modify the value
• Constant pointer: The pointer itself cannot point to a different address.
• int* const ptr = &num;
• // ptr = &anotherNum; // Error: Cannot change the pointer
• Constant pointer to a constant: Neither the pointer nor the value can be changed.
• const int* const ptr = &num;
• // *ptr = 20; // Error: Cannot modify the value
• // ptr = &anotherNum; // Error: Cannot change the pointer
10. Null Pointers

A null pointer does not point to any memory location. It is used to indicate that the pointer is not
initialized or is invalid.

Example:
int* ptr = nullptr; // Modern C++ (preferred)
int* ptr2 = NULL; // Older C++ (avoid)
int* ptr3 = 0; // Avoid (confusing)

11. Common Pitfalls

1. Dangling Pointers: Pointers that point to memory that has been freed.
2. int* ptr = new int;
3. delete ptr;
4. // ptr is now a dangling pointer
5. Memory Leaks: Forgetting to free dynamically allocated memory.
6. int* ptr = new int;
7. // Forgot to delete ptr
8. Uninitialized Pointers: Using a pointer before assigning it a valid address.
9. int* ptr;
10. *ptr = 10; // Undefined behavior

12. Best Practices

1. Always initialize pointers to nullptr or a valid address.


2. Use smart pointers (std::unique_ptr, std::shared_ptr) for automatic memory management.
3. Avoid raw pointers when possible; prefer references or smart pointers.
4. Always free dynamically allocated memory using delete or delete[].

Example: Program to Swap Two Numbers Using Pointers


#include <iostream>
using namespace std;

void swap(int* a, int* b) {


int temp = *a;
*a = *b;
*b = temp;
}

int main() {
int x = 10, y = 20;
swap(&x, &y);
cout << "x: " << x << ", y: " << y; // Output: x: 20, y: 10
return 0;
}
19. References
References in C++

References are aliases for existing variables. They provide an alternative way to access and
manipulate data without using pointers. References are safer and easier to use than pointers
because they cannot be null and cannot be reassigned to refer to a different variable.

1. Reference Declaration
Syntax:
data_type& reference_name = variable_name;
Example:
int num = 10;
int& ref = num; // ref is a reference to num

2. Using References

• A reference acts as an alias for the variable it refers to.


• Any changes made to the reference are reflected in the original variable.

Example:
int num = 10;
int& ref = num;

ref = 20; // Modifies num through ref


cout << num; // Output: 20

3. References vs. Pointers


Feature References Pointers

Declaration int& ref = num; int* ptr = &num;

Reassignment Cannot be reassigned Can be reassigned

Null Value Cannot be null Can be null

Memory Address Does not have its own memory address Has its own memory address

Syntax Easier to use (no dereferencing needed) Requires dereferencing (*ptr)


4. Passing References to Functions

References are commonly used to pass arguments to functions by reference, allowing the
function to modify the original variable.

Example:
void increment(int& ref) {
ref++; // Modifies the original variable
}

int main() {
int num = 10;
increment(num); // Passes num by reference
cout << num; // Output: 11
return 0;
}

5. Returning References from Functions

Functions can return references, but care must be taken to avoid returning references to local
variables (which go out of scope after the function ends).

Example:
int& getLarger(int& a, int& b) {
return (a > b) ? a : b;
}

int main() {
int x = 10, y = 20;
getLarger(x, y) = 30; // Modifies the larger variable (y)
cout << y; // Output: 30
return 0;
}

6. const References

• references prevent modification of the original variable.


const
• They are often used to pass large objects to functions without copying them.

Example:
void print(const int& ref) {
cout << ref; // Can read but not modify ref
}

int main() {
int num = 10;
print(num); // Passes num by const reference
return 0;
}
7. References and Arrays

References can be used to create aliases for arrays.

Example:
int arr[3] = {10, 20, 30};
int(&ref)[3] = arr; // ref is a reference to the array

cout << ref[1]; // Output: 20

8. Common Pitfalls

1. Uninitialized References:
o References must be initialized when declared.
2. int& ref; // Error: Reference must be initialized
3. Returning References to Local Variables:
o Returning a reference to a local variable results in undefined behavior.
4. int& badFunction() {
5. int num = 10;
6. return num; // Error: num goes out of scope
7. }

9. Best Practices

1. Use references to avoid copying large objects when passing them to functions.
2. Prefer const references when you don’t need to modify the original variable.
3. Avoid returning references to local variables.
4. Use references instead of pointers when possible for safer and cleaner code.

Example: Program to Swap Two Numbers Using References


#include <iostream>
using namespace std;

void swap(int& a, int& b) {


int temp = a;
a = b;
b = temp;
}

int main() {
int x = 10, y = 20;
swap(x, y); // Passes x and y by reference
cout << "x: " << x << ", y: " << y; // Output: x: 20, y: 10
return 0;
}
20. Date and Time
Date and Time in C++

C++ provides several ways to work with date and time:

1. C-style date and time (from the <ctime> library).


2. C++11 and later (using the <chrono> library).

1. C-Style Date and Time (<ctime>)

The <ctime> library provides functions to work with date and time in C-style.

a) time_t and tm Structures

• time_t: Represents the number of seconds since the Unix epoch (January 1, 1970).
• tm: A structure that holds date and time components (year, month, day, etc.).

Example:
#include <ctime>
#include <iostream>
using namespace std;

int main() {
time_t now = time(0); // Get current time
cout << "Seconds since epoch: " << now << endl;

tm* localTime = localtime(&now); // Convert to local time


cout << "Local time: " << asctime(localTime); // Output: Day Mon DD HH:MM:SS YYYY
return 0;
}
b) Common <ctime> Functions
Function Description Example

time(&t) Gets the current calendar time time_t now = time(0);

localtime(&t) Converts time_t to local time (tm) tm* localTime = localtime(&now);

gmtime(&t) Converts time_t to UTC time (tm) tm* utcTime = gmtime(&now);

asctime(tm*) Converts tm to a human-readable string cout << asctime(localTime);

strftime() Formats tm into a custom string See example below


c) Formatting Date and Time with strftime

The strftime function allows you to format date and time into a custom string.

Example:
#include <ctime>
#include <iostream>
using namespace std;

int main() {
time_t now = time(0);
tm* localTime = localtime(&now);

char buffer[80];
strftime(buffer, 80, "Today is %A, %B %d, %Y. Time: %I:%M %p", localTime);
cout << buffer << endl; // Output: Today is Monday, October 30, 2023. Time: 03:45 PM
return 0;
}

2. C++11 and Later (<chrono>)

The <chrono> library (introduced in C++11) provides a modern and type-safe way to work with
date and time.

a) std::chrono::system_clock

• Represents the system-wide real-time clock.


• Can be used to get the current time and convert it to different formats.

Example:
#include <chrono>
#include <iostream>
#include <ctime>
using namespace std;
using namespace std::chrono;

int main() {
// Get current time
auto now = system_clock::now();

// Convert to time_t
time_t now_time_t = system_clock::to_time_t(now);

// Convert to human-readable format


cout << "Current time: " << ctime(&now_time_t); // Output: Day Mon DD HH:MM:SS YYYY
return 0;
}
b) std::chrono::duration

• Represents a time interval (e.g., seconds, milliseconds).


• Can be used to measure elapsed time.

Example:
#include <chrono>
#include <iostream>
using namespace std;
using namespace std::chrono;

int main() {
auto start = high_resolution_clock::now(); // Start time

// Simulate some work


for (int i = 0; i < 1000000; i++) {}

auto end = high_resolution_clock::now(); // End time

// Calculate duration
auto duration = duration_cast<milliseconds>(end - start);
cout << "Time taken: " << duration.count() << " milliseconds" << endl;
return 0;
}

c) std::chrono::time_point

• Represents a specific point in time.


• Can be used to store and manipulate dates and times.

Example:
#include <chrono>
#include <iostream>
using namespace std;
using namespace std::chrono;

int main() {
// Get current time point
auto now = system_clock::now();

// Add 1 hour to the current time


auto oneHourLater = now + hours(1);

// Convert to time_t
time_t now_time_t = system_clock::to_time_t(now);
time_t later_time_t = system_clock::to_time_t(oneHourLater);

// Print results
cout << "Current time: " << ctime(&now_time_t);
cout << "One hour later: " << ctime(&later_time_t);
return 0;
}

3. Comparing C-Style and <chrono>


Feature C-Style (<ctime>) C++11 (<chrono>)

Type Safety Not type-safe Type-safe

Precision Limited to seconds Supports nanoseconds

Ease of Use Less intuitive More intuitive

Flexibility Limited formatting options Highly flexible

Portability Works on all systems Requires C++11 or later

4. Best Practices

1. Use <chrono> for modern C++ programs (C++11 and later).


2. Use <ctime> for compatibility with older codebases.
3. Prefer std::chrono::duration for measuring time intervals.
4. Use strftime for custom date and time formatting in C-style.

Example: Program to Display Current Date and Time


#include <chrono>
#include <iostream>
#include <ctime>
using namespace std;
using namespace std::chrono;

int main() {
// Get current time
auto now = system_clock::now();
time_t now_time_t = system_clock::to_time_t(now);

// Convert to human-readable format


cout << "Current time: " << ctime(&now_time_t);
return 0;
}
21. Basic Input/Output
Basic Input/Output in C++

Input and output (I/O) operations in C++ are performed using the Standard Input/Output
Library, which is part of the <iostream> header. The two most commonly used objects are:

1. cin: For input (from the keyboard).


2. cout: For output (to the console).

1. Output with cout

The cout object is used to display output on the console. It is used with the insertion operator
(<<).

Syntax:
cout << "Text or variable";
Example:
#include <iostream>
using namespace std;

int main() {
cout << "Hello, World!" << endl; // Output: Hello, World!
int num = 10;
cout << "The number is: " << num << endl; // Output: The number is: 10
return 0;
}

2. Input with cin

The cin object is used to read input from the keyboard. It is used with the extraction operator
(>>).

Syntax:
cin >> variable;
Example:
#include <iostream>
using namespace std;

int main() {
int num;
cout << "Enter a number: ";
cin >> num; // Reads input from the user
cout << "You entered: " << num << endl;
return 0;
}
3. Handling Multiple Inputs

You can use cin to read multiple inputs in a single statement.

Example:
#include <iostream>
using namespace std;

int main() {
int a, b;
cout << "Enter two numbers: ";
cin >> a >> b; // Reads two numbers
cout << "Sum: " << a + b << endl;
return 0;
}

4. Reading Strings

To read strings, use cin or getline().

a) Using cin

• cin reads input until the first whitespace character (space, tab, newline).

Example:
#include <iostream>
using namespace std;

int main() {
string name;
cout << "Enter your name: ";
cin >> name; // Reads a single word
cout << "Hello, " << name << "!" << endl;
return 0;
}
b) Using getline()

• getline() reads an entire line of input, including spaces.

Example:
#include <iostream>
using namespace std;

int main() {
string fullName;
cout << "Enter your full name: ";
getline(cin, fullName); // Reads the entire line
cout << "Hello, " << fullName << "!" << endl;
return 0;
}

5. Formatting Output

You can format output using manipulators from the <iomanip> library.

Common Manipulators:
Manipulator Description Example
endl Inserts a newline and flushes the stream cout << "Hello" << endl;

setw(n) Sets the field width for the next output cout << setw(10) << "Hello";

setprecision(n) Sets the decimal precision for floating-point numbers cout << setprecision(2) << 3.14159;

fixed Displays floating-point numbers in fixed notation cout << fixed << 3.14159;

scientific Displays floating-point numbers in scientific notation cout << scientific << 3.14159;

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

int main() {
double pi = 3.141592653589793;
cout << "Default: " << pi << endl;
cout << "Fixed (2 decimal places): " << fixed << setprecision(2) << pi << endl;
cout << "Scientific: " << scientific << pi << endl;
return 0;
}

6. Error Handling for Input

You can check if the input operation was successful using the fail() method.

Example:
#include <iostream>
using namespace std;

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

if (cin.fail()) {
cout << "Invalid input! Please enter a number." << endl;
cin.clear(); // Clears the error flag
cin.ignore(1000, '\n'); // Ignores the invalid input
} else {
cout << "You entered: " << num << endl;
}
return 0;
}

7. File Input/Output

C++ provides file streams (ifstream, ofstream) for reading from and writing to files.

a) Writing to a File
#include <iostream>
#include <fstream>
using namespace std;

int main() {
ofstream outFile("example.txt");
if (outFile.is_open()) {
outFile << "Hello, File!" << endl;
outFile.close();
} else {
cout << "Unable to open file!" << endl;
}
return 0;
}
b) Reading from a File
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main() {
ifstream inFile("example.txt");
string line;
if (inFile.is_open()) {
while (getline(inFile, line)) {
cout << line << endl;
}
inFile.close();
} else {
cout << "Unable to open file!" << endl;
}
return 0;
}
8. Best Practices

1. Use getline() for reading strings with spaces.


2. Always check for input errors using cin.fail().
3. Use <iomanip> for formatting output.
4. Close files after reading or writing to avoid resource leaks.

Example: Program to Read and Display User Information


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

int main() {
string name;
int age;
double salary;

cout << "Enter your name: ";


getline(cin, name);

cout << "Enter your age: ";


cin >> age;

cout << "Enter your salary: ";


cin >> salary;

cout << fixed << setprecision(2);


cout << "\nName: " << name << endl;
cout << "Age: " << age << endl;
cout << "Salary: $" << salary << endl;

return 0;
}

22. Data Structures


Data Structures in C++

Data structures are used to organize and store data efficiently. C++ provides several built-in
data structures, as well as the ability to create custom ones. Below is an overview of the most
commonly used data structures in C++.
1. Arrays

• Description: A collection of elements of the same type stored in contiguous memory


locations.
• Key Features:
o Fixed size.
o Fast access using indices.
• Example:

int arr[5] = {1, 2, 3, 4, 5};


cout << arr[2]; // Output: 3

2. Structures (struct)

• Description: A user-defined data type that groups related data members.


• Key Features:
o Can hold different data types.
o Members are accessed using the dot operator (.).
• Example:

struct Person {
string name;
int age;
};

Person p1 = {"John", 25};


cout << p1.name << " is " << p1.age << " years old."; // Output: John is 25 years old.

3. Classes (class)
• Description: Similar to structures but with access control (public, private, protected) and
methods.
• Key Features:
o Encapsulates data and functions.
o Supports OOP concepts like inheritance and polymorphism.
• Example:

class Rectangle {
private:
int width, height;
public:
Rectangle(int w, int h) : width(w), height(h) {}
int area() { return width * height; }
};

Rectangle rect(5, 10);


cout << "Area: " << rect.area(); // Output: Area: 50
4. Vectors (std::vector)

• Description: A dynamic array that can resize itself automatically.


• Key Features:
o Part of the Standard Template Library (STL).
o Provides methods like push_back(), pop_back(), and size().
• Example:

#include <vector>
using namespace std;

vector<int> nums = {1, 2, 3};


nums.push_back(4); // Adds 4 to the end
cout << nums[2]; // Output: 3

5. Linked Lists (std::list)


• Description: A sequence of elements where each element points to the next one.
• Key Features:
o Dynamic size.
o Efficient insertion and deletion.
• Example:

#include <list>
using namespace std;

list<int> nums = {1, 2, 3};


nums.push_back(4); // Adds 4 to the end
nums.push_front(0); // Adds 0 to the beginning
for (int num : nums) {
cout << num << " "; // Output: 0 1 2 3 4
}

6. Stacks (std::stack)
• Description: A Last-In-First-Out (LIFO) data structure.
• Key Features:
o Elements are added and removed from the top.
o Provides methods like push(), pop(), and top().
• Example:

#include <stack>
using namespace std;

stack<int> s;
s.push(10);
s.push(20);
cout << s.top(); // Output: 20
s.pop();
cout << s.top(); // Output: 10

7. Queues (std::queue)

• Description: A First-In-First-Out (FIFO) data structure.


• Key Features:
o Elements are added at the back and removed from the front.
o Provides methods like push(), pop(), and front().
• Example:

#include <queue>
using namespace std;

queue<int> q;
q.push(10);
q.push(20);
cout << q.front(); // Output: 10
q.pop();
cout << q.front(); // Output: 20

8. Maps (std::map)

• Description: A collection of key-value pairs where keys are unique.


• Key Features:
o Implemented as a balanced binary search tree.
o Provides methods like insert(), find(), and erase().
• Example:

#include <map>
using namespace std;

map<string, int> ages;


ages["John"] = 25;
ages["Jane"] = 30;
cout << ages["John"]; // Output: 25

9. Sets (std::set)

• Description: A collection of unique elements.


• Key Features:
o Implemented as a balanced binary search tree.
o Provides methods like insert(), find(), and erase().
• Example:

#include <set>
using namespace std;
set<int> nums = {1, 2, 3};
nums.insert(4);
nums.insert(2); // Duplicate, ignored
for (int num : nums) {
cout << num << " "; // Output: 1 2 3 4
}

10. Hash Tables (std::unordered_map)

• Description: A collection of key-value pairs with average constant-time complexity for


lookups.
• Key Features:
o Implemented using hash tables.
o Provides methods like insert(), find(), and erase().
• Example:

#include <unordered_map>
using namespace std;

unordered_map<string, int> ages;


ages["John"] = 25;
ages["Jane"] = 30;
cout << ages["John"]; // Output: 25

11. Custom Data Structures


You can create custom data structures by combining arrays, structs, classes, and pointers.

Example: Linked List Implementation


struct Node {
int data;
Node* next;
};

class LinkedList {
private:
Node* head;
public:
LinkedList() : head(nullptr) {}
void append(int value) {
Node* newNode = new Node{value, nullptr};
if (!head) {
head = newNode;
} else {
Node* temp = head;
while (temp->next) {
temp = temp->next;
}
temp->next = newNode;
}
}
void print() {
Node* temp = head;
while (temp) {
cout << temp->data << " ";
temp = temp->next;
}
}
};

int main() {
LinkedList list;
list.append(10);
list.append(20);
list.append(30);
list.print(); // Output: 10 20 30
return 0;
}

12. Best Practices


1. Use STL containers (e.g., vector, map) for most use cases.
2. Prefer std::unordered_map over std::map for faster lookups (if order is not important).
3. Use custom data structures only when necessary.
4. Always manage dynamic memory carefully to avoid leaks.

23. Classes and Objects


Classes and Objects in C++
Classes and objects are the foundation of Object-Oriented Programming (OOP) in C++. A
class is a blueprint for creating objects, and an object is an instance of a class.

1. Class Definition
A class defines the properties (attributes) and behaviors (methods) of objects.

Syntax:
class ClassName {
// Access specifiers: private, public, protected
private:
// Private members (not accessible outside the class)
public:
// Public members (accessible outside the class)
// Constructor(s)
// Methods
};
Example:
class Rectangle {
private:
int width, height;
public:
// Constructor
Rectangle(int w, int h) : width(w), height(h) {}

// Method to calculate area


int area() {
return width * height;
}
};

2. Object Creation
An object is an instance of a class. You can create objects using the class name.

Syntax:
ClassName objectName(arguments);
Example:
Rectangle rect(5, 10); // Creates an object of Rectangle
cout << "Area: " << rect.area(); // Output: Area: 50

3. Access Specifiers

Access specifiers define the accessibility of class members:

• private: Members are accessible only within the class.


• public: Members are accessible from outside the class.
• protected: Members are accessible within the class and by derived classes.

Example:
class Person {
private:
string name;
int age;
public:
void setName(string n) {
name = n;
}
void setAge(int a) {
age = a;
}
void display() {
cout << "Name: " << name << ", Age: " << age << endl;
}
};

int main() {
Person p;
p.setName("John");
p.setAge(25);
p.display(); // Output: Name: John, Age: 25
return 0;
}

4. Constructors and Destructors


a) Constructors

• Special methods that are called when an object is created.


• Used to initialize objects.

Example:
class Rectangle {
private:
int width, height;
public:
// Parameterized constructor
Rectangle(int w, int h) : width(w), height(h) {}

// Default constructor
Rectangle() : width(0), height(0) {}

int area() {
return width * height;
}
};

int main() {
Rectangle rect1(5, 10); // Calls parameterized constructor
Rectangle rect2; // Calls default constructor
cout << "Area: " << rect1.area() << endl; // Output: Area: 50
cout << "Area: " << rect2.area() << endl; // Output: Area: 0
return 0;
}
b) Destructors

• Special methods that are called when an object is destroyed.


• Used to release resources.

Example:
class Rectangle {
private:
int width, height;
public:
Rectangle(int w, int h) : width(w), height(h) {}
~Rectangle() {
cout << "Rectangle destroyed!" << endl;
}
int area() {
return width * height;
}
};

int main() {
Rectangle rect(5, 10);
cout << "Area: " << rect.area() << endl; // Output: Area: 50
// Destructor is called automatically when rect goes out of scope
return 0;
}

5. Member Functions

Member functions are functions defined inside a class. They can access all members of the class.

Example:
class Circle {
private:
double radius;
public:
Circle(double r) : radius(r) {}
double area() {
return 3.14159 * radius * radius;
}
double circumference() {
return 2 * 3.14159 * radius;
}
};

int main() {
Circle c(5);
cout << "Area: " << c.area() << endl; // Output: Area: 78.5397
cout << "Circumference: " << c.circumference() << endl; // Output: Circumference: 31.4159
return 0;
}

6. Static Members
Static members belong to the class rather than individual objects. They are shared by all objects
of the class.

Example:
class Counter {
private:
static int count; // Static member
public:
Counter() {
count++;
}
static int getCount() { // Static member function
return count;
}
};

int Counter::count = 0; // Initialize static member

int main() {
Counter c1, c2, c3;
cout << "Count: " << Counter::getCount() << endl; // Output: Count: 3
return 0;
}

7. Friend Functions and Classes

Friend functions and classes can access private and protected members of a class.

a) Friend Function
class Rectangle {
private:
int width, height;
public:
Rectangle(int w, int h) : width(w), height(h) {}
friend void printArea(Rectangle r); // Friend function
};

void printArea(Rectangle r) {
cout << "Area: " << r.width * r.height << endl;
}

int main() {
Rectangle rect(5, 10);
printArea(rect); // Output: Area: 50
return 0;
}
b) Friend Class
class Rectangle {
private:
int width, height;
public:
Rectangle(int w, int h) : width(w), height(h) {}
friend class Printer; // Friend class
};

class Printer {
public:
void printArea(Rectangle r) {
cout << "Area: " << r.width * r.height << endl;
}
};
int main() {
Rectangle rect(5, 10);
Printer p;
p.printArea(rect); // Output: Area: 50
return 0;
}

8. Inheritance

Inheritance allows a class to inherit properties and behaviors from another class.

Example:
class Shape {
protected:
int width, height;
public:
Shape(int w, int h) : width(w), height(h) {}
};

class Rectangle : public Shape {


public:
Rectangle(int w, int h) : Shape(w, h) {}
int area() {
return width * height;
}
};

int main() {
Rectangle rect(5, 10);
cout << "Area: " << rect.area() << endl; // Output: Area: 50
return 0;
}

9. Polymorphism

Polymorphism allows objects of different classes to be treated as objects of a common base class.

Example:
class Shape {
public:
virtual void draw() {
cout << "Drawing a shape" << endl;
}
};

class Circle : public Shape {


public:
void draw() override {
cout << "Drawing a circle" << endl;
}
};

int main() {
Shape* shape = new Circle();
shape->draw(); // Output: Drawing a circle
delete shape;
return 0;
}

10. Best Practices

1. Use access specifiers to enforce encapsulation.


2. Prefer initialization lists in constructors.
3. Use const for methods that do not modify the object.
4. Avoid friend functions/classes unless necessary.
5. Use inheritance and polymorphism to promote code reuse.

24. Inheritance
Inheritance in C++
Inheritance is a fundamental concept in Object-Oriented Programming (OOP) that allows a
class (called the derived class) to inherit properties and behaviors (methods) from another class
(called the base class). This promotes code reuse and establishes a hierarchical relationship
between classes.

1. Base and Derived Classes

• Base Class (Parent Class): The class whose properties and methods are inherited.
• Derived Class (Child Class): The class that inherits from the base class.

Syntax:
class BaseClass {
// Base class members
};

class DerivedClass : access_specifier BaseClass {


// Derived class members
};

• access_specifier: Can
be public, private, or protected. It determines the accessibility of the base
class members in the derived class.
2. Types of Inheritance
a) Single Inheritance

• A derived class inherits from one base class.

Example:
class Animal {
public:
void eat() {
cout << "Eating..." << endl;
}
};

class Dog : public Animal {


public:
void bark() {
cout << "Barking..." << endl;
}
};

int main() {
Dog dog;
dog.eat(); // Output: Eating...
dog.bark(); // Output: Barking...
return 0;
}

b) Multiple Inheritance

• A derived class inherits from multiple base classes.

Example:
class A {
public:
void displayA() {
cout << "Class A" << endl;
}
};

class B {
public:
void displayB() {
cout << "Class B" << endl;
}
};

class C : public A, public B {


public:
void displayC() {
cout << "Class C" << endl;
}
};
int main() {
C obj;
obj.displayA(); // Output: Class A
obj.displayB(); // Output: Class B
obj.displayC(); // Output: Class C
return 0;
}

c) Multilevel Inheritance

• A derived class inherits from another derived class.

Example:
class Animal {
public:
void eat() {
cout << "Eating..." << endl;
}
};

class Dog : public Animal {


public:
void bark() {
cout << "Barking..." << endl;
}
};

class Puppy : public Dog {


public:
void weep() {
cout << "Weeping..." << endl;
}
};

int main() {
Puppy puppy;
puppy.eat(); // Output: Eating...
puppy.bark(); // Output: Barking...
puppy.weep(); // Output: Weeping...
return 0;
}

d) Hierarchical Inheritance

• Multiple derived classes inherit from a single base class.

Example:
class Animal {
public:
void eat() {
cout << "Eating..." << endl;
}
};

class Dog : public Animal {


public:
void bark() {
cout << "Barking..." << endl;
}
};

class Cat : public Animal {


public:
void meow() {
cout << "Meowing..." << endl;
}
};

int main() {
Dog dog;
dog.eat(); // Output: Eating...
dog.bark(); // Output: Barking...

Cat cat;
cat.eat(); // Output: Eating...
cat.meow(); // Output: Meowing...
return 0;
}

e) Hybrid Inheritance

• A combination of multiple and multilevel inheritance.

Example:
class A {
public:
void displayA() {
cout << "Class A" << endl;
}
};

class B : public A {
public:
void displayB() {
cout << "Class B" << endl;
}
};

class C {
public:
void displayC() {
cout << "Class C" << endl;
}
};
class D : public B, public C {
public:
void displayD() {
cout << "Class D" << endl;
}
};

int main() {
D obj;
obj.displayA(); // Output: Class A
obj.displayB(); // Output: Class B
obj.displayC(); // Output: Class C
obj.displayD(); // Output: Class D
return 0;
}

3. Access Specifiers in Inheritance


The access specifier used in inheritance determines the accessibility of the base class members
in the derived class.

Access Specifier Base Class Member Access Derived Class Access

public public → public public members remain public in derived class.


protected → protected protected members remain protected in derived class.

private → inaccessible private members are not accessible in derived class.

protected public → protected public members become protected in derived class.

protected → protected protected members remain protected in derived class.

private → inaccessible private members are not accessible in derived class.

private public → private public members become private in derived class.

protected → private protected members become private in derived class.

private → inaccessible private members are not accessible in derived class.


4. Constructor and Destructor in Inheritance

• Constructors: Base class constructors are called before derived class constructors.
• Destructors: Derived class destructors are called before base class destructors.

Example:
class Base {
public:
Base() {
cout << "Base Constructor" << endl;
}
~Base() {
cout << "Base Destructor" << endl;
}
};

class Derived : public Base {


public:
Derived() {
cout << "Derived Constructor" << endl;
}
~Derived() {
cout << "Derived Destructor" << endl;
}
};

int main() {
Derived obj;
return 0;
}
Output:
Base Constructor
Derived Constructor
Derived Destructor
Base Destructor

5. Function Overriding

• A derived class can override a method of the base class to provide its own
implementation.
• Use the override keyword (C++11 and later) to explicitly indicate overriding.

Example:
class Animal {
public:
virtual void sound() {
cout << "Animal sound" << endl;
}
};

class Dog : public Animal {


public:
void sound() override {
cout << "Bark" << endl;
}
};

int main() {
Animal* animal = new Dog();
animal->sound(); // Output: Bark
delete animal;
return 0;
}

6. Best Practices

1. Use public inheritance for "is-a" relationships.


2. Avoid multiple inheritance unless necessary (it can lead to complexity).
3. Use virtual functions to enable polymorphism.
4. Prefer composition over inheritance when possible.

25. Overloading (Operator & Function)


Overloading in C++

Overloading allows you to define multiple functions or operators with the same name but
different parameters or behaviors. There are two types of overloading in C++:

1. Function Overloading
2. Operator Overloading

1. Function Overloading

Function overloading allows you to define multiple functions with the same name but different
parameters.

Rules:

• Functions must have the same name.


• Functions must differ in the number or type of parameters.
• Return type does not contribute to overloading.

Example:
#include <iostream>
using namespace std;
// Function to add two integers
int add(int a, int b) {
return a + b;
}

// Function to add three integers


int add(int a, int b, int c) {
return a + b + c;
}

// Function to add two doubles


double add(double a, double b) {
return a + b;
}

int main() {
cout << add(5, 10) << endl; // Output: 15 (calls int add(int, int))
cout << add(5, 10, 15) << endl; // Output: 30 (calls int add(int, int, int))
cout << add(3.5, 2.5) << endl; // Output: 6.0 (calls double add(double, double))
return 0;
}

2. Operator Overloading

Operator overloading allows you to define custom behavior for operators when used with user-
defined types (e.g., classes).

Syntax:
return_type operator symbol (parameters) {
// Custom behavior
}
Example:
#include <iostream>
using namespace std;

class Complex {
private:
double real, imag;
public:
Complex(double r = 0, double i = 0) : real(r), imag(i) {}

// Overload the + operator


Complex operator + (const Complex& obj) {
Complex temp;
temp.real = real + obj.real;
temp.imag = imag + obj.imag;
return temp;
}

// Overload the << operator for output


friend ostream& operator << (ostream& out, const Complex& obj);
};

// Define the << operator


ostream& operator << (ostream& out, const Complex& obj) {
out << obj.real << " + " << obj.imag << "i";
return out;
}

int main() {
Complex c1(3, 4), c2(1, 2);
Complex c3 = c1 + c2; // Uses overloaded + operator
cout << c3 << endl; // Output: 4 + 6i
return 0;
}

3. Commonly Overloaded Operators


Operator Description Example

+ Addition Complex operator + (const Complex& obj)

- Subtraction Complex operator - (const Complex& obj)

* Multiplication Complex operator * (const Complex& obj)

/ Division Complex operator / (const Complex& obj)

== Equality comparison bool operator == (const Complex& obj)

<< Output (insertion) ostream& operator << (ostream& out, const Complex& obj)

>> Input (extraction) istream& operator >> (istream& in, Complex& obj)

4. Overloading Unary Operators

Unary operators (e.g., ++, --, -) can also be overloaded.


Example:
class Counter {
private:
int count;
public:
Counter(int c = 0) : count(c) {}

// Overload the ++ operator (prefix)


Counter operator ++ () {
return Counter(++count);
}

// Overload the ++ operator (postfix)


Counter operator ++ (int) {
return Counter(count++);
}

void display() {
cout << "Count: " << count << endl;
}
};

int main() {
Counter c1(5);
Counter c2 = ++c1; // Prefix
c2.display(); // Output: Count: 6

Counter c3 = c1++; // Postfix


c3.display(); // Output: Count: 6
c1.display(); // Output: Count: 7
return 0;
}

5. Overloading Assignment Operator (=)


The assignment operator can be overloaded to handle deep copying of objects.

Example:
class MyString {
private:
char* str;
public:
MyString(const char* s = "") {
str = new char[strlen(s) + 1];
strcpy(str, s);
}

// Overload the assignment operator


MyString& operator = (const MyString& obj) {
if (this != &obj) { // Check for self-assignment
delete[] str; // Free existing memory
str = new char[strlen(obj.str) + 1];
strcpy(str, obj.str);
}
return *this;
}

void display() {
cout << str << endl;
}

~MyString() {
delete[] str;
}
};

int main() {
MyString s1("Hello"), s2;
s2 = s1; // Uses overloaded = operator
s2.display(); // Output: Hello
return 0;
}

6. Best Practices
1. Use function overloading to provide multiple ways to perform similar tasks.
2. Use operator overloading to make user-defined types behave like built-in types.
3. Avoid overloading operators in a way that makes the code less intuitive.
4. Always handle self-assignment when overloading the assignment operator.

26. Polymorphism
Polymorphism in C++
Polymorphism is a core concept in Object-Oriented Programming (OOP) that allows objects
of different classes to be treated as objects of a common base class. It enables flexibility and
extensibility in code by allowing a single interface to represent different underlying forms (data
types).

1. Types of Polymorphism

Polymorphism in C++ can be categorized into two types:

1. Compile-Time Polymorphism (Static Binding)


o Achieved through function overloading and operator overloading.
o The function to be executed is determined at compile time.
2. Run-Time Polymorphism (Dynamic Binding)
o Achieved through function overriding and virtual functions.
o The function to be executed is determined at run time.

2. Compile-Time Polymorphism
a) Function Overloading

• Multiple functions with the same name but different parameters.

Example:
#include <iostream>
using namespace std;

void print(int i) {
cout << "Integer: " << i << endl;
}

void print(double d) {
cout << "Double: " << d << endl;
}

int main() {
print(5); // Output: Integer: 5
print(3.14); // Output: Double: 3.14
return 0;
}
b) Operator Overloading

• Defining custom behavior for operators when used with user-defined types.

Example:
#include <iostream>
using namespace std;

class Complex {
private:
double real, imag;
public:
Complex(double r = 0, double i = 0) : real(r), imag(i) {}

// Overload the + operator


Complex operator + (const Complex& obj) {
return Complex(real + obj.real, imag + obj.imag);
}

void display() {
cout << real << " + " << imag << "i" << endl;
}
};

int main() {
Complex c1(3, 4), c2(1, 2);
Complex c3 = c1 + c2; // Uses overloaded + operator
c3.display(); // Output: 4 + 6i
return 0;
}

3. Run-Time Polymorphism
Run-time polymorphism is achieved using virtual functions and function overriding.

a) Function Overriding

• A derived class provides a specific implementation of a method that is already defined


in its base class.

Example:
#include <iostream>
using namespace std;

class Animal {
public:
virtual void sound() {
cout << "Animal sound" << endl;
}
};

class Dog : public Animal {


public:
void sound() override {
cout << "Bark" << endl;
}
};

class Cat : public Animal {


public:
void sound() override {
cout << "Meow" << endl;
}
};

int main() {
Animal* animal1 = new Dog();
Animal* animal2 = new Cat();

animal1->sound(); // Output: Bark


animal2->sound(); // Output: Meow

delete animal1;
delete animal2;
return 0;
}
b) Virtual Functions

• A function declared in the base class using the virtual keyword.


• Allows the derived class to override the function.

Example:
#include <iostream>
using namespace std;

class Shape {
public:
virtual void draw() {
cout << "Drawing a shape" << endl;
}
};

class Circle : public Shape {


public:
void draw() override {
cout << "Drawing a circle" << endl;
}
};

class Square : public Shape {


public:
void draw() override {
cout << "Drawing a square" << endl;
}
};

int main() {
Shape* shape1 = new Circle();
Shape* shape2 = new Square();

shape1->draw(); // Output: Drawing a circle


shape2->draw(); // Output: Drawing a square

delete shape1;
delete shape2;
return 0;
}

4. Pure Virtual Functions and Abstract Classes

• A pure virtual function is a virtual function with no implementation.


• A class containing at least one pure virtual function is called an abstract class.
• Abstract classes cannot be instantiated and are meant to be inherited.

Syntax:
virtual return_type function_name() = 0;
Example:
#include <iostream>
using namespace std;

class Shape {
public:
virtual void draw() = 0; // Pure virtual function
};

class Circle : public Shape {


public:
void draw() override {
cout << "Drawing a circle" << endl;
}
};

class Square : public Shape {


public:
void draw() override {
cout << "Drawing a square" << endl;
}
};

int main() {
Shape* shape1 = new Circle();
Shape* shape2 = new Square();

shape1->draw(); // Output: Drawing a circle


shape2->draw(); // Output: Drawing a square

delete shape1;
delete shape2;
return 0;
}

5. Virtual Destructors

• If a base class pointer points to a derived class object, the base class destructor will be
called when the object is deleted, leading to memory leaks.
• To avoid this, declare the base class destructor as virtual.

Example:
#include <iostream>
using namespace std;

class Base {
public:
virtual ~Base() {
cout << "Base destructor" << endl;
}
};

class Derived : public Base {


public:
~Derived() {
cout << "Derived destructor" << endl;
}
};

int main() {
Base* obj = new Derived();
delete obj; // Calls both Derived and Base destructors
return 0;
}
Output:
Derived destructor
Base destructor

6. Best Practices

1. Use virtual functions to enable run-time polymorphism.


2. Declare the base class destructor as virtual if the class is meant to be inherited.
3. Use abstract classes to define interfaces for derived classes.
4. Prefer compile-time polymorphism for performance-critical code.

27. Data Abstraction


• Abstraction: Hide implementation details.

Data Abstraction in C++


Data abstraction is a fundamental concept in Object-Oriented Programming (OOP) that
involves hiding the implementation details of a class and exposing only the essential features
to the user. It allows you to focus on what an object does rather than how it does it.

1. Key Concepts of Data Abstraction

1. Separation of Interface and Implementation:


o The interface (public methods) defines what operations can be performed.
o The implementation (private methods and data) defines how these operations are
performed.
2. Focus on Essential Features:
o Expose only the necessary details to the user.
o Hide the complex and unnecessary details.
3. Encapsulation and Abstraction:
o Encapsulation bundles data and methods into a single unit (class).
o Abstraction hides the internal details and exposes only the functionality.
2. Access Specifiers
C++ provides three access specifiers to control the visibility of class members:

• public: Members are accessible from anywhere.


• private: Members are accessible only within the class.
• protected: Members are accessible within the class and by derived classes.

Example:
class Employee {
private:
string name; // Private data member
int salary; // Private data member

public:
// Public methods to access private data
void setName(string n) {
name = n;
}
string getName() {
return name;
}
void setSalary(int s) {
salary = s;
}
int getSalary() {
return salary;
}
};

3. Abstract Classes and Pure Virtual Functions

An abstract class is a class that cannot be instantiated and is meant to be inherited. It contains
at least one pure virtual function.

Syntax:
virtual return_type function_name() = 0;
Example:
#include <iostream>
using namespace std;

// Abstract class
class Shape {
public:
// Pure virtual function
virtual void draw() = 0;
};
// Derived class
class Circle : public Shape {
public:
void draw() override {
cout << "Drawing a circle" << endl;
}
};

// Derived class
class Square : public Shape {
public:
void draw() override {
cout << "Drawing a square" << endl;
}
};

int main() {
Shape* shape1 = new Circle();
Shape* shape2 = new Square();

shape1->draw(); // Output: Drawing a circle


shape2->draw(); // Output: Drawing a square

delete shape1;
delete shape2;
return 0;
}

4. Benefits of Data Abstraction


1. Simplifies Complexity:
o Users interact with a simplified interface without worrying about internal details.
2. Improves Maintainability:
o Changes to the internal implementation do not affect the external interface.
3. Enhances Security:
o Sensitive data and implementation details are hidden from the user.
4. Promotes Reusability:
o Abstract classes and interfaces can be reused across different parts of the
program.

5. Example: Abstraction in a Bank Account Class


#include <iostream>
using namespace std;

class BankAccount {
private:
string accountNumber;
double balance;

public:
// Constructor
BankAccount(string accNum, double bal) : accountNumber(accNum), balance(bal) {}

// Getter for account number


string getAccountNumber() {
return accountNumber;
}

// Getter for balance


double getBalance() {
return balance;
}

// Method to deposit money


void deposit(double amount) {
if (amount > 0) {
balance += amount;
cout << "Deposited: $" << amount << endl;
} else {
cout << "Invalid deposit amount!" << endl;
}
}

// Method to withdraw money


void withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
cout << "Withdrawn: $" << amount << endl;
} else {
cout << "Invalid withdrawal amount!" << endl;
}
}
};

int main() {
BankAccount acc("123456789", 1000);

cout << "Account Number: " << acc.getAccountNumber() << endl;


cout << "Initial Balance: $" << acc.getBalance() << endl;

acc.deposit(500);
cout << "Balance after deposit: $" << acc.getBalance() << endl;

acc.withdraw(200);
cout << "Balance after withdrawal: $" << acc.getBalance() << endl;

acc.withdraw(2000); // Invalid withdrawal


return 0;
}

6. Best Practices
1. Use Access Specifiers:
o Declare data members as private to enforce encapsulation and abstraction.
2. Provide Public Methods:
o Expose only the necessary methods to interact with the class.
3. Use Abstract Classes:
o Define interfaces using abstract classes and pure virtual functions.
4. Hide Implementation Details:
o Avoid exposing internal logic and data structures.

28. Data Encapsulation


• Encapsulation: Bundle data and methods that operate on the data.

Data Encapsulation in C++

Data encapsulation is a fundamental concept in Object-Oriented Programming (OOP) that


involves bundling data (attributes) and methods (functions) that operate on the data into a
single unit, called a class. It also restricts direct access to some of an object's components, which
is a way of preventing unintended interference and misuse of the data.

1. Key Concepts of Data Encapsulation


1. Data Hiding:
o Restricting direct access to data members by making them private.
o Access is provided through public methods (getters and setters).
2. Abstraction:
o Exposing only the necessary details and hiding the implementation.
3. Encapsulation:
o Combining data and methods into a single unit (class) and controlling access to
them.

2. Access Specifiers

C++ provides three access specifiers to control the visibility of class members:

• public: Members are accessible from anywhere.


• private: Members are accessible only within the class.
• protected: Members are accessible within the class and by derived classes.

Example:
class Employee {
private:
string name; // Private data member
int salary; // Private data member
public:
// Public methods to access private data
void setName(string n) {
name = n;
}
string getName() {
return name;
}
void setSalary(int s) {
salary = s;
}
int getSalary() {
return salary;
}
};

3. Getters and Setters


• Getters: Methods used to retrieve the value of private data members.
• Setters: Methods used to modify the value of private data members.

Example:
#include <iostream>
using namespace std;

class Employee {
private:
string name;
int salary;

public:
// Setter for name
void setName(string n) {
name = n;
}

// Getter for name


string getName() {
return name;
}

// Setter for salary


void setSalary(int s) {
if (s > 0) { // Validation
salary = s;
} else {
cout << "Invalid salary!" << endl;
}
}

// Getter for salary


int getSalary() {
return salary;
}
};

int main() {
Employee emp;
emp.setName("John Doe");
emp.setSalary(50000);

cout << "Name: " << emp.getName() << endl;


cout << "Salary: $" << emp.getSalary() << endl;

emp.setSalary(-1000); // Invalid salary


return 0;
}

4. Benefits of Data Encapsulation

1. Control Over Data:


o Prevents unauthorized access and modification of data.
o Allows validation and constraints to be applied through setters.
2. Code Maintainability:
o Changes to the internal implementation do not affect the external interface.
3. Reusability:
o Encapsulated classes can be reused in different parts of the program.
4. Security:
o Sensitive data is hidden from external access.

5. Example: Encapsulation in a Bank Account Class


#include <iostream>
using namespace std;

class BankAccount {
private:
string accountNumber;
double balance;

public:
// Constructor
BankAccount(string accNum, double bal) : accountNumber(accNum), balance(bal) {}

// Getter for account number


string getAccountNumber() {
return accountNumber;
}

// Getter for balance


double getBalance() {
return balance;
}
// Method to deposit money
void deposit(double amount) {
if (amount > 0) {
balance += amount;
cout << "Deposited: $" << amount << endl;
} else {
cout << "Invalid deposit amount!" << endl;
}
}

// Method to withdraw money


void withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
cout << "Withdrawn: $" << amount << endl;
} else {
cout << "Invalid withdrawal amount!" << endl;
}
}
};

int main() {
BankAccount acc("123456789", 1000);

cout << "Account Number: " << acc.getAccountNumber() << endl;


cout << "Initial Balance: $" << acc.getBalance() << endl;

acc.deposit(500);
cout << "Balance after deposit: $" << acc.getBalance() << endl;

acc.withdraw(200);
cout << "Balance after withdrawal: $" << acc.getBalance() << endl;

acc.withdraw(2000); // Invalid withdrawal


return 0;
}

6. Best Practices
1. Make Data Members Private:
o Always declare data members as private to enforce encapsulation.
2. Use Getters and Setters:
o Provide public methods to access and modify private data members.
3. Validate Data:
o Use setters to validate data before modifying private members.
4. Avoid Exposing Implementation Details:
o Expose only the necessary methods and hide the internal logic.
29. Interfaces
Interfaces in C++

In C++, interfaces are implemented using abstract classes with pure virtual functions. An
interface defines a contract that derived classes must follow by implementing all the pure virtual
functions. Interfaces are used to achieve abstraction and polymorphism.

1. What is an Interface?

An interface is a class that:

• Contains only pure virtual functions (no implementation).


• Cannot be instantiated.
• Is meant to be inherited by other classes.

Syntax:
class InterfaceName {
public:
virtual return_type function_name() = 0; // Pure virtual function
};

2. Creating an Interface

To create an interface:

1. Declare a class with pure virtual functions.


2. Derived classes must implement all pure virtual functions.

Example:
#include <iostream>
using namespace std;

// Interface
class Drawable {
public:
virtual void draw() = 0; // Pure virtual function
};

// Derived class implementing the interface


class Circle : public Drawable {
public:
void draw() override {
cout << "Drawing a circle" << endl;
}
};
// Derived class implementing the interface
class Square : public Drawable {
public:
void draw() override {
cout << "Drawing a square" << endl;
}
};

int main() {
Drawable* shape1 = new Circle();
Drawable* shape2 = new Square();

shape1->draw(); // Output: Drawing a circle


shape2->draw(); // Output: Drawing a square

delete shape1;
delete shape2;
return 0;
}

3. Multiple Interfaces
A class can implement multiple interfaces by inheriting from multiple abstract classes.

Example:
#include <iostream>
using namespace std;

// First interface
class Drawable {
public:
virtual void draw() = 0;
};

// Second interface
class Resizable {
public:
virtual void resize(int factor) = 0;
};

// Derived class implementing both interfaces


class Circle : public Drawable, public Resizable {
public:
void draw() override {
cout << "Drawing a circle" << endl;
}
void resize(int factor) override {
cout << "Resizing circle by factor " << factor << endl;
}
};

int main() {
Circle circle;
circle.draw(); // Output: Drawing a circle
circle.resize(2); // Output: Resizing circle by factor 2
return 0;
}

4. Benefits of Interfaces
1. Abstraction:
o Hides implementation details and exposes only the functionality.
2. Polymorphism:
o Allows objects of different classes to be treated as objects of a common interface.
3. Flexibility:
o Enables loose coupling between classes.
4. Reusability:
o Interfaces can be reused across different parts of the program.

5. Example: Interface for a Payment System


#include <iostream>
using namespace std;

// Interface for payment methods


class PaymentMethod {
public:
virtual void pay(double amount) = 0;
};

// Derived class implementing the interface


class CreditCard : public PaymentMethod {
public:
void pay(double amount) override {
cout << "Paying $" << amount << " via Credit Card" << endl;
}
};

// Derived class implementing the interface


class PayPal : public PaymentMethod {
public:
void pay(double amount) override {
cout << "Paying $" << amount << " via PayPal" << endl;
}
};

int main() {
PaymentMethod* payment1 = new CreditCard();
PaymentMethod* payment2 = new PayPal();

payment1->pay(100); // Output: Paying $100 via Credit Card


payment2->pay(50); // Output: Paying $50 via PayPal

delete payment1;
delete payment2;
return 0;
}

6. Best Practices

1. Use Pure Virtual Functions:


o Define interfaces using pure virtual functions.
2. Avoid Data Members:
o Interfaces should not contain data members (only methods).
3. Follow Naming Conventions:
o Use meaningful names for interfaces (e.g., Drawable, Resizable).
4. Implement All Methods:
o Derived classes must implement all pure virtual functions.

30. Files and Streams


Files and Streams in C++

Files and streams are used to handle input and output operations in C++. The <fstream> library
provides classes for working with files, while the <iostream> library handles standard input/output
streams.

1. File Stream Classes

C++ provides three main classes for file handling:

1. ofstream: Used for writing to files.


2. ifstream: Used for reading from files.
3. fstream: Used for both reading and writing.

2. Opening and Closing Files


a) Opening a File

• Use the open() method or the constructor to open a file.


• Specify the file mode (e.g., ios::in, ios::out, ios::app).

b) Closing a File

• Use the close() method to close a file.


Example:
#include <fstream>
using namespace std;

int main() {
ofstream outFile;
outFile.open("example.txt", ios::out); // Open file for writing
if (outFile.is_open()) {
outFile << "Hello, File!" << endl;
outFile.close(); // Close the file
} else {
cout << "Unable to open file!" << endl;
}
return 0;
}

3. Writing to a File
Use the ofstream class to write data to a file.

Example:
#include <fstream>
using namespace std;

int main() {
ofstream outFile("example.txt");
if (outFile.is_open()) {
outFile << "This is line 1." << endl;
outFile << "This is line 2." << endl;
outFile.close();
} else {
cout << "Unable to open file!" << endl;
}
return 0;
}

4. Reading from a File

Use the ifstream class to read data from a file.

Example:
#include <fstream>
#include <iostream>
using namespace std;

int main() {
ifstream inFile("example.txt");
string line;
if (inFile.is_open()) {
while (getline(inFile, line)) {
cout << line << endl;
}
inFile.close();
} else {
cout << "Unable to open file!" << endl;
}
return 0;
}

5. File Modes

File modes determine how a file is opened. Common modes include:

Mode Description

ios::in Open for input (reading).

ios::out Open for output (writing).

ios::app Append to the end of the file.

ios::ate Open and seek to the end of the file.

ios::trunc Truncate the file (delete contents).

ios::binary Open in binary mode.

Example:
ofstream outFile("example.txt", ios::out | ios::app); // Open for appending

6. Binary File Operations

Binary files store data in binary format, which is more efficient for non-text data.

a) Writing to a Binary File


#include <fstream>
using namespace std;

int main() {
ofstream outFile("data.bin", ios::binary);
if (outFile.is_open()) {
int data = 12345;
outFile.write((char*)&data, sizeof(data)); // Write binary data
outFile.close();
} else {
cout << "Unable to open file!" << endl;
}
return 0;
}
b) Reading from a Binary File
#include <fstream>
#include <iostream>
using namespace std;

int main() {
ifstream inFile("data.bin", ios::binary);
if (inFile.is_open()) {
int data;
inFile.read((char*)&data, sizeof(data)); // Read binary data
cout << "Data: " << data << endl;
inFile.close();
} else {
cout << "Unable to open file!" << endl;
}
return 0;
}

7. File Position Pointers

File position pointers track the current position in a file. You can manipulate them using:

• tellg() / tellp(): Get the current position.


• seekg() / seekp(): Set the position.

Example:
#include <fstream>
#include <iostream>
using namespace std;

int main() {
fstream file("example.txt", ios::in | ios::out);
if (file.is_open()) {
file << "Hello, World!" << endl;

// Move to the beginning of the file


file.seekg(0, ios::beg);

string line;
getline(file, line);
cout << "First line: " << line << endl;

file.close();
} else {
cout << "Unable to open file!" << endl;
}
return 0;
}
8. Error Handling

Always check if a file was successfully opened before performing operations.

Example:
#include <fstream>
#include <iostream>
using namespace std;

int main() {
ifstream inFile("nonexistent.txt");
if (!inFile) {
cout << "Error: File not found!" << endl;
} else {
string line;
while (getline(inFile, line)) {
cout << line << endl;
}
inFile.close();
}
return 0;
}

9. Best Practices

1. Check File Open Status:


o Always verify if a file was successfully opened.
2. Close Files Properly:
o Use the close() method to release resources.
3. Use Binary Mode for Non-Text Data:
o Binary mode is more efficient for storing complex data structures.
4. Handle Errors Gracefully:
o Provide meaningful error messages for file operations.

31. Exception Handling


Exception Handling in C++

Exception handling is a mechanism to handle runtime errors gracefully. It allows you to


separate error-handling code from normal code, making programs more robust and
maintainable.
1. Key Concepts

1. Exception:
o An abnormal condition that occurs during program execution (e.g., division by
zero, file not found).
2. Try Block:
o A block of code where exceptions may occur. It is followed by one or more catch
blocks.
3. Catch Block:
o A block of code that handles exceptions thrown by the try block.
4. Throw Statement:
o Used to raise an exception explicitly.

2. Basic Syntax
try {
// Code that may throw an exception
if (errorCondition) {
throw exception; // Throw an exception
}
} catch (exceptionType& e) {
// Handle the exception
}

3. Example: Handling Division by Zero


#include <iostream>
using namespace std;

int main() {
int numerator, denominator;
cout << "Enter numerator and denominator: ";
cin >> numerator >> denominator;

try {
if (denominator == 0) {
throw "Division by zero error!"; // Throw a string exception
}
cout << "Result: " << numerator / denominator << endl;
} catch (const char* e) {
cout << "Error: " << e << endl;
}

return 0;
}

4. Standard Exceptions
C++ provides a set of standard exception classes in the <stdexcept> header. These include:
• std::runtime_error
• std::logic_error
• std::out_of_range
• std::invalid_argument

Example:
#include <iostream>
#include <stdexcept>
using namespace std;

int main() {
try {
throw runtime_error("A runtime error occurred!");
} catch (const runtime_error& e) {
cout << "Caught exception: " << e.what() << endl;
}
return 0;
}

5. Multiple Catch Blocks


You can have multiple catch blocks to handle different types of exceptions.

Example:
#include <iostream>
using namespace std;

int main() {
try {
int choice;
cout << "Enter 1 for int, 2 for double, 3 for string: ";
cin >> choice;

if (choice == 1) {
throw 42; // Throw an int
} else if (choice == 2) {
throw 3.14; // Throw a double
} else if (choice == 3) {
throw string("Hello"); // Throw a string
} else {
throw invalid_argument("Invalid choice!"); // Throw a standard exception
}
} catch (int e) {
cout << "Caught int: " << e << endl;
} catch (double e) {
cout << "Caught double: " << e << endl;
} catch (const string& e) {
cout << "Caught string: " << e << endl;
} catch (const invalid_argument& e) {
cout << "Caught exception: " << e.what() << endl;
}
return 0;
}
6. Rethrowing Exceptions

You can rethrow an exception in a catch block to pass it to an outer try-catch block.

Example:
#include <iostream>
using namespace std;

void innerFunction() {
try {
throw runtime_error("Error in inner function!");
} catch (const runtime_error& e) {
cout << "Inner function caught: " << e.what() << endl;
throw; // Rethrow the exception
}
}

int main() {
try {
innerFunction();
} catch (const runtime_error& e) {
cout << "Main function caught: " << e.what() << endl;
}
return 0;
}

7. Custom Exception Classes

You can create custom exception classes by inheriting from std::exception.

Example:
#include <iostream>
#include <exception>
using namespace std;

class MyException : public exception {


public:
const char* what() const noexcept override {
return "Custom exception occurred!";
}
};

int main() {
try {
throw MyException();
} catch (const MyException& e) {
cout << "Caught exception: " << e.what() << endl;
}
return 0;
}
8. Best Practices

1. Catch Specific Exceptions:


o Catch specific exceptions rather than using a generic catch (...).
2. Avoid Throwing Raw Types:
o Use standard or custom exception classes instead of raw types (e.g., int, char*).
3. Clean Up Resources:
o Use RAII (Resource Acquisition Is Initialization) to ensure resources are
released even if an exception is thrown.
4. Document Exceptions:
o Document the exceptions that a function can throw.

9. Example: File Handling with Exception Handling


#include <iostream>
#include <fstream>
#include <stdexcept>
using namespace std;

void readFile(const string& filename) {


ifstream file(filename);
if (!file) {
throw runtime_error("Unable to open file: " + filename);
}
string line;
while (getline(file, line)) {
cout << line << endl;
}
file.close();
}

int main() {
try {
readFile("nonexistent.txt");
} catch (const runtime_error& e) {
cout << "Error: " << e.what() << endl;
}
return 0;
}
32. Dynamic Memory
Dynamic Memory in C++

Dynamic memory allocation allows you to allocate memory at runtime instead of compile time.
This is useful when the amount of memory needed is not known in advance or when you need to
manage memory manually.

1. Dynamic Memory Allocation

C++ provides two operators for dynamic memory allocation:

1. new: Allocates memory.


2. delete: Deallocates memory.

Syntax:
pointer = new data_type; // Allocate memory for a single element
pointer = new data_type[size]; // Allocate memory for an array

delete pointer; // Deallocate memory for a single element


delete[] pointer; // Deallocate memory for an array

2. Allocating Memory for a Single Element


Example:
#include <iostream>
using namespace std;

int main() {
int* ptr = new int; // Allocate memory for an integer
*ptr = 42; // Assign a value
cout << "Value: " << *ptr << endl; // Output: Value: 42
delete ptr; // Deallocate memory
return 0;
}

3. Allocating Memory for an Array


Example:
#include <iostream>
using namespace std;

int main() {
int size = 5;
int* arr = new int[size]; // Allocate memory for an array

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


arr[i] = i + 1; // Initialize array
}

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


cout << arr[i] << " "; // Output: 1 2 3 4 5
}

delete[] arr; // Deallocate memory


return 0;
}

4. Common Pitfalls

1. Memory Leaks:
o Forgetting to deallocate memory using delete or delete[].
2. int* ptr = new int;
3. // Forgot to delete ptr;
4. Dangling Pointers:
o Using a pointer after the memory it points to has been deallocated.
5. int* ptr = new int;
6. delete ptr;
7. *ptr = 10; // Undefined behavior
8. Double Deletion:
o Deallocating the same memory block twice.
9. int* ptr = new int;
10. delete ptr;
11. delete ptr; // Undefined behavior

5. Smart Pointers (C++11 and later)

Smart pointers automatically manage dynamic memory, preventing memory leaks and dangling
pointers. The <memory> header provides three types of smart pointers:

1. std::unique_ptr: Manages a single object with exclusive ownership.


2. std::shared_ptr: Manages an object with shared ownership.
3. std::weak_ptr: A non-owning reference to an object managed by std::shared_ptr.

Example:
#include <iostream>
#include <memory> // For smart pointers
using namespace std;

int main() {
// Unique pointer
unique_ptr<int> ptr1(new int(42));
cout << "Value: " << *ptr1 << endl; // Output: Value: 42

// Shared pointer
shared_ptr<int> ptr2(new int(100));
cout << "Value: " << *ptr2 << endl; // Output: Value: 100
// Weak pointer
weak_ptr<int> ptr3 = ptr2;
if (auto sharedPtr = ptr3.lock()) {
cout << "Value: " << *sharedPtr << endl; // Output: Value: 100
}

// No need to manually delete; memory is automatically released


return 0;
}

6. Dynamic Memory for Objects

You can allocate memory for objects dynamically.

Example:
#include <iostream>
using namespace std;

class MyClass {
public:
MyClass() {
cout << "Constructor called!" << endl;
}
~MyClass() {
cout << "Destructor called!" << endl;
}
void display() {
cout << "Hello, World!" << endl;
}
};

int main() {
MyClass* obj = new MyClass(); // Allocate memory for an object
obj->display(); // Output: Hello, World!
delete obj; // Deallocate memory
return 0;
}

7. Best Practices

1. Use Smart Pointers:


o Prefer std::unique_ptr or std::shared_ptr over raw pointers.
2. Avoid Manual Memory Management:
o Use RAII (Resource Acquisition Is Initialization) to manage resources.
3. Check for Allocation Failures:
o Handle cases where new fails to allocate memory (e.g., using std::nothrow).
4. Avoid Dangling Pointers:
o Set pointers to nullptr after deleting them.
8. Example: Dynamic Array with Exception Handling
#include <iostream>
#include <new> // For std::nothrow
using namespace std;

int main() {
int size = 1000000000; // Very large size
int* arr = new (nothrow) int[size]; // Allocate memory without throwing an exception

if (!arr) {
cout << "Memory allocation failed!" << endl;
} else {
for (int i = 0; i < size; i++) {
arr[i] = i + 1;
}
delete[] arr; // Deallocate memory
}

return 0;
}

33. Namespaces
Namespaces in C++
Namespaces are used to organize code and prevent name conflicts in large programs. They
allow you to group related classes, functions, and variables under a unique name.

1. Defining a Namespace
Use the namespace keyword to define a namespace.

Syntax:
namespace NamespaceName {
// Classes, functions, variables, etc.
}
Example:
#include <iostream>
using namespace std;

namespace Math {
int add(int a, int b) {
return a + b;
}
}

int main() {
cout << Math::add(5, 10) << endl; // Output: 15
return 0;
}

2. Accessing Namespace Members

You can access namespace members using the scope resolution operator (::).

Example:
#include <iostream>
using namespace std;

namespace Math {
int add(int a, int b) {
return a + b;
}
}

int main() {
int result = Math::add(5, 10); // Access using ::
cout << "Result: " << result << endl; // Output: Result: 15
return 0;
}

3. The using Directive

The using directive allows you to bring all members of a namespace into the current scope.

Example:
#include <iostream>
using namespace std;

namespace Math {
int add(int a, int b) {
return a + b;
}
}

using namespace Math; // Bring all Math members into the current scope

int main() {
cout << add(5, 10) << endl; // Output: 15
return 0;
}

4. Nested Namespaces
Namespaces can be nested inside other namespaces.
Example:
#include <iostream>
using namespace std;

namespace Outer {
namespace Inner {
void display() {
cout << "Inside Inner namespace" << endl;
}
}
}

int main() {
Outer::Inner::display(); // Output: Inside Inner namespace
return 0;
}

5. Anonymous Namespaces

An anonymous namespace is a namespace without a name. Its members have internal linkage,
meaning they are only accessible within the same file.

Example:
#include <iostream>
using namespace std;

namespace {
void display() {
cout << "Inside anonymous namespace" << endl;
}
}

int main() {
display(); // Output: Inside anonymous namespace
return 0;
}

6. Namespace Aliases

You can create an alias for a namespace to simplify its usage.

Example:
#include <iostream>
using namespace std;

namespace VeryLongNamespaceName {
void display() {
cout << "Inside VeryLongNamespaceName" << endl;
}
}
namespace VLN = VeryLongNamespaceName; // Create an alias

int main() {
VLN::display(); // Output: Inside VeryLongNamespaceName
return 0;
}

7. The std Namespace

The std namespace contains all the standard C++ library components (e.g., cout, cin, vector).

Example:
#include <iostream>
#include <vector>
using namespace std;

int main() {
vector<int> nums = {1, 2, 3};
for (int num : nums) {
cout << num << " "; // Output: 1 2 3
}
return 0;
}

8. Best Practices
1. Avoid using namespace std:
o Prefer using std:: explicitly to avoid name conflicts.
2. Use Namespaces to Organize Code:
o Group related classes, functions, and variables under meaningful namespaces.
3. Avoid Global Namespaces:
o Minimize the use of the global namespace to prevent name clashes.
4. Use Namespace Aliases:
o Simplify long namespace names with aliases.

9. Example: Custom Namespace for a Library


#include <iostream>
using namespace std;

namespace MyLibrary {
namespace Math {
int add(int a, int b) {
return a + b;
}
}
namespace String {
string reverse(string str) {
return string(str.rbegin(), str.rend());
}
}
}

int main() {
cout << MyLibrary::Math::add(5, 10) << endl; // Output: 15
cout << MyLibrary::String::reverse("Hello") << endl; // Output: olleH
return 0;
}

34. Templates
Templates in C++

Templates are a powerful feature in C++ that allow you to write generic and reusable code.
They enable you to define functions and classes that work with any data type.

1. Function Templates
A function template allows you to define a function that can operate on different data types.

Syntax:
template <typename T>
return_type function_name(parameters) {
// Function body
}
Example:
#include <iostream>
using namespace std;

// Function template to add two numbers


template <typename T>
T add(T a, T b) {
return a + b;
}

int main() {
cout << add(5, 10) << endl; // Output: 15 (int)
cout << add(3.5, 2.5) << endl; // Output: 6.0 (double)
cout << add(string("Hello, "), string("World!")) << endl; // Output: Hello, World! (string)
return 0;
}
2. Class Templates

A class template allows you to define a class that can work with different data types.

Syntax:
template <typename T>
class ClassName {
// Class members
};
Example:
#include <iostream>
using namespace std;

// Class template for a Box


template <typename T>
class Box {
private:
T value;
public:
Box(T v) : value(v) {}
T getValue() {
return value;
}
};

int main() {
Box<int> intBox(42);
Box<string> strBox("Hello");

cout << "Int Box: " << intBox.getValue() << endl; // Output: Int Box: 42
cout << "String Box: " << strBox.getValue() << endl; // Output: String Box: Hello
return 0;
}

3. Multiple Template Parameters


You can define templates with multiple parameters.

Example:
#include <iostream>
using namespace std;

// Function template with two parameters


template <typename T1, typename T2>
void printPair(T1 a, T2 b) {
cout << "(" << a << ", " << b << ")" << endl;
}

int main() {
printPair(5, 3.14); // Output: (5, 3.14)
printPair("Hello", 42); // Output: (Hello, 42)
return 0;
}

4. Template Specialization

Template specialization allows you to define a specific implementation of a template for a


particular data type.

Example:
#include <iostream>
using namespace std;

// General template
template <typename T>
void printType(T value) {
cout << "Generic: " << value << endl;
}

// Specialization for int


template <>
void printType<int>(int value) {
cout << "Specialized for int: " << value << endl;
}

int main() {
printType(3.14); // Output: Generic: 3.14
printType(42); // Output: Specialized for int: 42
return 0;
}

5. Non-Type Template Parameters


Templates can also take non-type parameters, such as integers or pointers.

Example:
#include <iostream>
using namespace std;

// Template with a non-type parameter


template <typename T, int size>
class Array {
private:
T arr[size];
public:
void set(int index, T value) {
arr[index] = value;
}
T get(int index) {
return arr[index];
}
};
int main() {
Array<int, 5> intArray;
intArray.set(0, 10);
cout << "Value at index 0: " << intArray.get(0) << endl; // Output: Value at index 0: 10
return 0;
}

6. Variadic Templates (C++11 and later)

Variadic templates allow you to define templates that accept a variable number of arguments.

Example:
#include <iostream>
using namespace std;

// Base case for recursion


void print() {
cout << "End of list" << endl;
}

// Variadic template
template <typename T, typename... Args>
void print(T first, Args... args) {
cout << first << endl;
print(args...); // Recursive call
}

int main() {
print(1, 3.14, "Hello", 42); // Output: 1, 3.14, Hello, 42, End of list
return 0;
}

7. Best Practices

1. Use Templates for Generic Code:


o Templates are ideal for writing reusable code that works with multiple data types.
2. Avoid Overusing Templates:
o Overusing templates can make code harder to read and debug.
3. Use Template Specialization Sparingly:
o Specialization can lead to code duplication; use it only when necessary.
4. Document Template Parameters:
o Clearly document the purpose and requirements of template parameters.

8. Example: Template for a Generic Stack


#include <iostream>
using namespace std;
template <typename T, int maxSize>
class Stack {
private:
T arr[maxSize];
int top;
public:
Stack() : top(-1) {}

void push(T value) {


if (top < maxSize - 1) {
arr[++top] = value;
} else {
cout << "Stack overflow!" << endl;
}
}

T pop() {
if (top >= 0) {
return arr[top--];
} else {
cout << "Stack underflow!" << endl;
return T(); // Return default value
}
}
};

int main() {
Stack<int, 5> intStack;
intStack.push(10);
intStack.push(20);
cout << "Popped: " << intStack.pop() << endl; // Output: Popped: 20
cout << "Popped: " << intStack.pop() << endl; // Output: Popped: 10
return 0;
}

35. Preprocessor
Preprocessor in C++

The preprocessor is a tool that processes the source code before it is compiled. It performs tasks
like including files, defining macros, and conditional compilation. Preprocessor directives
begin with a # symbol.

1. Common Preprocessor Directives


Directive Description
#include Includes a file in the source code.
#define Defines a macro.

#undef Undefines a macro.

#if, #elif, #else, #endif Conditional compilation.

#ifdef, #ifndef Checks if a macro is defined.


#pragma Provides additional instructions to the compiler.

2. #include Directive

The #include directive is used to include the contents of a file in the source code.

Example:
#include <iostream> // Include the standard iostream library
using namespace std;

int main() {
cout << "Hello, World!" << endl;
return 0;
}

3. #define Directive
The #define directive is used to define macros, which are replaced by the preprocessor before
compilation.

Example:
#include <iostream>
using namespace std;

#define PI 3.14159 // Define a macro for PI

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

4. Macros with Arguments


Macros can also take arguments, similar to functions.

Example:
#include <iostream>
using namespace std;
#define SQUARE(x) ((x) * (x)) // Macro with argument

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

5. Conditional Compilation

Conditional compilation allows you to include or exclude code based on certain conditions.

Example:
#include <iostream>
using namespace std;

#define DEBUG // Define DEBUG macro

int main() {
#ifdef DEBUG
cout << "Debug mode is on!" << endl; // Output: Debug mode is on!
#else
cout << "Debug mode is off!" << endl;
#endif

return 0;
}

6. #if, #elif, #else, #endif

These directives allow you to compile code based on conditions.

Example:
#include <iostream>
using namespace std;

#define VERSION 2

int main() {
#if VERSION == 1
cout << "Version 1" << endl;
#elif VERSION == 2
cout << "Version 2" << endl; // Output: Version 2
#else
cout << "Unknown version" << endl;
#endif

return 0;
}
7. #pragma Directive

The #pragma directive provides additional instructions to the compiler. It is compiler-specific.

Example:
#include <iostream>
using namespace std;

#pragma message("Compiling this file...") // Display a message during compilation

int main() {
cout << "Hello, World!" << endl;
return 0;
}

8. #undef Directive

The #undef directive is used to undefine a macro.

Example:
#include <iostream>
using namespace std;

#define DEBUG

int main() {
#ifdef DEBUG
cout << "Debug mode is on!" << endl; // Output: Debug mode is on!
#endif

#undef DEBUG // Undefine DEBUG

#ifdef DEBUG
cout << "Debug mode is still on!" << endl;
#else
cout << "Debug mode is off!" << endl; // Output: Debug mode is off!
#endif

return 0;
}

9. Predefined Macros

C++ provides several predefined macros that give information about the compilation
environment.

Macro Description
__LINE__ Current line number.

__FILE__ Current file name.

__DATE__ Current date (in "MMM DD YYYY" format).

__TIME__ Current time (in "HH:MM:SS" format).

__cplusplus Version of the C++ standard being used.

Example:
#include <iostream>
using namespace std;

int main() {
cout << "Line: " << __LINE__ << endl; // Output: Line: 6
cout << "File: " << __FILE__ << endl; // Output: File: [filename]
cout << "Date: " << __DATE__ << endl; // Output: Date: [current date]
cout << "Time: " << __TIME__ << endl; // Output: Time: [current time]
cout << "C++ Version: " << __cplusplus << endl; // Output: C++ Version: [version]
return 0;
}

10. Best Practices

1. Use #include Wisely:


o Avoid including unnecessary files to reduce compilation time.
2. Avoid Complex Macros:
o Prefer inline functions or templates over complex macros.
3. Use Conditional Compilation Sparingly:
o Overuse can make code harder to read and maintain.
4. Document Macros:
o Clearly document the purpose of macros and their usage.

11. Example: Debugging with Macros


#include <iostream>
using namespace std;

#define DEBUG // Define DEBUG macro

#ifdef DEBUG
#define LOG(msg) cout << "DEBUG: " << msg << endl
#else
#define LOG(msg) // Define LOG as nothing in non-debug mode
#endif

int main() {
LOG("Starting program..."); // Output: DEBUG: Starting program...
cout << "Hello, World!" << endl;
LOG("Ending program..."); // Output: DEBUG: Ending program...
return 0;
}

36. Signal Handling


Signal Handling in C++

Signal handling is a mechanism to handle asynchronous events (signals) that occur during
program execution, such as interrupts or exceptions. C++ provides the <csignal> library to
handle signals.

1. Common Signals
Signal Description

SIGINT Interrupt signal (e.g., Ctrl+C).

SIGTERM Termination request.

SIGSEGV Invalid memory access (segmentation fault).

SIGFPE Floating-point exception (e.g., division by zero).

SIGABRT Abnormal termination (e.g., abort()).

2. Handling Signals

Use the signal() function to register a signal handler.

Syntax:
void (*signal(int sig, void (*handler)(int)))(int);

• sig: The signal to handle (e.g., SIGINT).


• handler: The function to handle the signal.

Example:
#include <iostream>
#include <csignal>
using namespace std;
// Signal handler function
void signalHandler(int signum) {
cout << "Interrupt signal (" << signum << ") received." << endl;
exit(signum); // Terminate program
}

int main() {
// Register signal handler for SIGINT
signal(SIGINT, signalHandler);

while (true) {
cout << "Press Ctrl+C to exit..." << endl;
sleep(1); // Simulate work
}

return 0;
}

3. Raising Signals

You can raise signals programmatically using the raise() function.

Syntax:
int raise(int sig);
Example:
#include <iostream>
#include <csignal>
using namespace std;

void signalHandler(int signum) {


cout << "Signal (" << signum << ") received." << endl;
exit(signum);
}

int main() {
signal(SIGINT, signalHandler);

cout << "Raising a signal..." << endl;


raise(SIGINT); // Raise SIGINT

return 0;
}

4. Ignoring Signals

You can ignore signals by setting the handler to SIG_IGN.

Example:
#include <iostream>
#include <csignal>
using namespace std;

int main() {
// Ignore SIGINT
signal(SIGINT, SIG_IGN);

cout << "Press Ctrl+C to test signal handling..." << endl;


while (true) {
// Infinite loop
}

return 0;
}

5. Default Signal Handling

You can restore the default signal handler using SIG_DFL.

Example:
#include <iostream>
#include <csignal>
using namespace std;

void signalHandler(int signum) {


cout << "Custom signal handler called." << endl;
signal(signum, SIG_DFL); // Restore default handler
}

int main() {
signal(SIGINT, signalHandler);

cout << "Press Ctrl+C once to trigger custom handler, then again to terminate." << endl;
while (true) {
// Infinite loop
}

return 0;
}

6. Handling Multiple Signals

You can handle multiple signals using a single handler.

Example:
#include <iostream>
#include <csignal>
using namespace std;

void signalHandler(int signum) {


switch (signum) {
case SIGINT:
cout << "SIGINT received." << endl;
break;
case SIGTERM:
cout << "SIGTERM received." << endl;
break;
default:
cout << "Unknown signal received." << endl;
}
exit(signum);
}

int main() {
signal(SIGINT, signalHandler);
signal(SIGTERM, signalHandler);

cout << "Press Ctrl+C or send SIGTERM to test signal handling..." << endl;
while (true) {
// Infinite loop
}

return 0;
}

7. Best Practices

1. Avoid Complex Logic in Signal Handlers:


o Signal handlers should be simple and fast. Avoid complex operations like I/O or
memory allocation.
2. Use Atomic Variables:
o If you need to share data between the signal handler and the main program, use
atomic variables or volatile variables.
3. Restore Default Handlers:
o Restore default signal handlers after handling the signal to avoid unexpected
behavior.
4. Document Signal Handling:
o Clearly document the signals your program handles and their behavior.

8. Example: Graceful Shutdown


#include <iostream>
#include <csignal>
#include <atomic>
using namespace std;

atomic<bool> shutdownFlag(false);

void signalHandler(int signum) {


cout << "Shutdown signal received." << endl;
shutdownFlag = true;
}
int main() {
signal(SIGINT, signalHandler);
signal(SIGTERM, signalHandler);

cout << "Press Ctrl+C or send SIGTERM to initiate shutdown..." << endl;
while (!shutdownFlag) {
// Simulate work
}

cout << "Shutting down gracefully..." << endl;


return 0;
}

37. Multithreading

Multithreading is a powerful feature in C++ that allows you to execute multiple threads
concurrently, enabling better utilization of CPU resources and improving the performance of
applications, especially those that perform I/O operations or need to handle multiple tasks
simultaneously.

Key Concepts in Multithreading


1. Thread: A thread is the smallest unit of execution within a process. Multiple threads can
run concurrently within the same process, sharing the same memory space.
2. Concurrency: The ability of a program to execute multiple tasks simultaneously.
3. Parallelism: A subset of concurrency where tasks are executed at the same time on
multiple CPU cores.
4. Synchronization: Ensuring that multiple threads access shared resources in a controlled
manner to avoid race conditions.
5. Race Condition: A situation where the behavior of a program depends on the relative
timing of events, such as the order in which threads are scheduled.

Multithreading in C++
C++ provides multithreading support through the <thread> library, introduced in C++11. Below
are the key components and techniques for working with threads in C++.

1. Creating Threads
You can create a thread using the std::thread class. The thread starts executing as soon as it is
created.
Example:
#include <iostream>
#include <thread>
using namespace std;

void task() {
cout << "Thread is running!" << endl;
}

int main() {
thread t1(task); // Create a thread that executes the task function
t1.join(); // Wait for the thread to finish
cout << "Main thread continues..." << endl;
return 0;
}
Explanation:

• thread t1(task);: Creates a thread t1 that executes the task function.


• t1.join();: Waits for the thread t1 to complete before proceeding.

2. Passing Arguments to Threads


You can pass arguments to the thread function by including them in the thread constructor.

Example:
#include <iostream>
#include <thread>
using namespace std;

void printMessage(const string& message) {


cout << "Message: " << message << endl;
}

int main() {
thread t1(printMessage, "Hello from thread!");
t1.join();
return 0;
}

3. Detaching Threads

A thread can be detached using the detach() method. A detached thread runs independently, and
the main thread does not wait for it to finish.

Example:
#include <iostream>
#include <thread>
using namespace std;
void task() {
cout << "Thread is running!" << endl;
}

int main() {
thread t1(task);
t1.detach(); // Detach the thread
cout << "Main thread continues..." << endl;
// The program may terminate before the thread finishes
return 0;
}

4. Thread Synchronization

When multiple threads access shared resources, synchronization is required to avoid race
conditions. C++ provides several synchronization mechanisms:

• Mutex (std::mutex): A mutual exclusion object used to protect shared resources.


• Lock Guards (std::lock_guard): Automatically locks and unlocks a mutex.
• Condition Variables (std::condition_variable): Used to block threads until a condition is
met.

Example: Using Mutex


#include <iostream>
#include <thread>
#include <mutex>
using namespace std;

mutex mtx; // Mutex for synchronization

void printNumbers(int id) {


lock_guard<mutex> lock(mtx); // Automatically locks and unlocks the mutex
for (int i = 0; i < 5; i++) {
cout << "Thread " << id << ": " << i << endl;
}
}

int main() {
thread t1(printNumbers, 1);
thread t2(printNumbers, 2);

t1.join();
t2.join();

return 0;
}
5. Race Conditions

A race condition occurs when multiple threads access shared data simultaneously, leading to
unpredictable results.

Example: Race Condition


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

int sharedValue = 0;

void increment() {
for (int i = 0; i < 100000; i++) {
sharedValue++;
}
}

int main() {
thread t1(increment);
thread t2(increment);

t1.join();
t2.join();

cout << "Final value: " << sharedValue << endl; // May not be 200000
return 0;
}
Fixing the Race Condition with Mutex
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;

int sharedValue = 0;
mutex mtx;

void increment() {
for (int i = 0; i < 100000; i++) {
lock_guard<mutex> lock(mtx);
sharedValue++;
}
}

int main() {
thread t1(increment);
thread t2(increment);

t1.join();
t2.join();

cout << "Final value: " << sharedValue << endl; // Will be 200000
return 0;
}
6. Condition Variables

Condition variables are used to block threads until a specific condition is met. They are often
used with mutexes.

Example: Producer-Consumer Problem


#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
using namespace std;

queue<int> buffer;
mutex mtx;
condition_variable cv;
const int maxSize = 5;

void producer(int id) {


for (int i = 0; i < 10; i++) {
unique_lock<mutex> lock(mtx);
cv.wait(lock, [] { return buffer.size() < maxSize; }); // Wait if buffer is full
buffer.push(i);
cout << "Producer " << id << " produced: " << i << endl;
lock.unlock();
cv.notify_all(); // Notify consumers
}
}

void consumer(int id) {


for (int i = 0; i < 10; i++) {
unique_lock<mutex> lock(mtx);
cv.wait(lock, [] { return !buffer.empty(); }); // Wait if buffer is empty
int value = buffer.front();
buffer.pop();
cout << "Consumer " << id << " consumed: " << value << endl;
lock.unlock();
cv.notify_all(); // Notify producers
}
}

int main() {
thread p1(producer, 1);
thread c1(consumer, 1);

p1.join();
c1.join();

return 0;
}
7. Thread Safety

• Use mutexes to protect shared resources.


• Avoid global variables when possible.
• Use thread-safe data structures from the STL (e.g., std::atomic).

8. Thread Pooling

Thread pooling is a technique where a fixed number of threads are created to handle tasks. This
avoids the overhead of creating and destroying threads repeatedly.

Example: Simple Thread Pool


#include <iostream>
#include <thread>
#include <vector>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <functional>
using namespace std;

class ThreadPool {
public:
ThreadPool(size_t numThreads) {
for (size_t i = 0; i < numThreads; i++) {
workers.emplace_back([this] {
while (true) {
function<void()> task;
{
unique_lock<mutex> lock(queueMutex);
cv.wait(lock, [this] { return !tasks.empty() || stop; });
if (stop && tasks.empty()) return;
task = move(tasks.front());
tasks.pop();
}
task();
}
});
}
}

void enqueue(function<void()> task) {


{
unique_lock<mutex> lock(queueMutex);
tasks.push(task);
}
cv.notify_one();
}

~ThreadPool() {
{
unique_lock<mutex> lock(queueMutex);
stop = true;
}
cv.notify_all();
for (thread& worker : workers) {
worker.join();
}
}

private:
vector<thread> workers;
queue<function<void()>> tasks;
mutex queueMutex;
condition_variable cv;
bool stop = false;
};

int main() {
ThreadPool pool(4);

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


pool.enqueue([i] {
cout << "Task " << i << " is running on thread " << this_thread::get_id() << endl;
});
}

return 0;
}

Best Practices for Multithreading


1. Minimize Shared Data: Reduce the need for synchronization by minimizing shared data.
2. Use RAII for Locks: Use std::lock_guard or std::unique_lock to ensure locks are released
automatically.
3. Avoid Deadlocks: Ensure that locks are acquired in a consistent order.
4. Test Thoroughly: Multithreaded programs can have subtle bugs, so test extensively.

38. Web Programming


• CGI Programming:
#include <iostream>
using namespace std;

int main() {
cout << "Content-type:text/html\r\n\r\n";
cout << "<html><body><h1>Hello, World!</h1></body></html>";
return 0;
}
39. STL Tutorial

The Standard Template Library (STL) is a powerful library in C++ that provides a collection
of template classes and functions for common data structures and algorithms. It is a core part of
the C++ Standard Library and is widely used for efficient and reusable code.

Key Components of STL


The STL consists of four main components:

1. Containers: Data structures to store and organize data.


2. Algorithms: Functions to perform operations on containers (e.g., sorting, searching).
3. Iterators: Objects used to traverse elements in containers.
4. Functors: Function objects that can be used as arguments to algorithms.

1. Containers
Containers are data structures that store collections of objects. STL provides several types of
containers:

Sequence Containers
• std::vector: Dynamic array.
• std::list: Doubly linked list.
• std::deque: Double-ended queue.
• std::array: Fixed-size array (introduced in C++11).

Associative Containers

• std::set: Collection of unique keys.


• std::map: Collection of key-value pairs with unique keys.
• std::multiset: Collection of keys, allowing duplicates.
• std::multimap: Collection of key-value pairs, allowing duplicate keys.

Unordered Containers

• std::unordered_set: Hash-based set.


• std::unordered_map: Hash-based map.
• std::unordered_multiset: Hash-based multiset.
• std::unordered_multimap: Hash-based multimap.
Container Adapters

• std::stack: LIFO (Last-In-First-Out) stack.


• std::queue: FIFO (First-In-First-Out) queue.
• std::priority_queue: Priority queue.

2. Algorithms
STL provides a wide range of algorithms that operate on containers. These include:

• Sorting: std::sort, std::stable_sort


• Searching: std::find, std::binary_search
• Modifying: std::copy, std::transform
• Numeric: std::accumulate, std::inner_product

3. Iterators
Iterators are used to traverse elements in containers. They act as pointers to container elements.
Common iterator types include:

• Input Iterators: Read-only access.


• Output Iterators: Write-only access.
• Forward Iterators: Read and write access, moves forward.
• Bidirectional Iterators: Moves forward and backward.
• Random Access Iterators: Direct access to any element.

4. Functors
Functors are objects that can be used as if they were functions. They are often used as arguments
to algorithms.

STL Examples
1. Vector (std::vector)
A dynamic array that can resize itself automatically.

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

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

// Add elements
numbers.push_back(6);

// Access elements
cout << "First element: " << numbers[0] << endl;

// Iterate using a range-based for loop


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

// Size of the vector


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

return 0;
}

2. Map (std::map)

A collection of key-value pairs with unique keys, sorted by keys.

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

int main() {
map<string, int> ages;

// Insert elements
ages["Alice"] = 25;
ages["Bob"] = 30;

// Access elements
cout << "Alice's age: " << ages["Alice"] << endl;

// Iterate using iterators


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

return 0;
}

3. Set (std::set)
A collection of unique keys, sorted by keys.
#include <iostream>
#include <set>
using namespace std;

int main() {
set<int> numbers = {3, 1, 4, 1, 5, 9}; // Duplicates are ignored

// Insert elements
numbers.insert(2);

// Check if an element exists


if (numbers.find(4) != numbers.end()) {
cout << "4 is in the set!" << endl;
}

// Iterate using iterators


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

return 0;
}

4. Algorithms (std::sort, std::find)

STL algorithms operate on containers.

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

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

// Sort the vector


sort(numbers.begin(), numbers.end());

// Find an element
auto it = find(numbers.begin(), numbers.end(), 3);
if (it != numbers.end()) {
cout << "Found 3 at position: " << distance(numbers.begin(), it) << endl;
}

// Print sorted vector


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

return 0;
}
5. Stack (std::stack)

A LIFO (Last-In-First-Out) data structure.

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

int main() {
stack<int> s;

// Push elements
s.push(10);
s.push(20);
s.push(30);

// Pop elements
while (!s.empty()) {
cout << s.top() << " "; // Access the top element
s.pop(); // Remove the top element
}
cout << endl;

return 0;
}

6. Queue (std::queue)

A FIFO (First-In-First-Out) data structure.

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

int main() {
queue<int> q;

// Push elements
q.push(10);
q.push(20);
q.push(30);

// Pop elements
while (!q.empty()) {
cout << q.front() << " "; // Access the front element
q.pop(); // Remove the front element
}
cout << endl;

return 0;
}
7. Priority Queue (std::priority_queue)

A queue where elements are ordered by priority.

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

int main() {
priority_queue<int> pq;

// Push elements
pq.push(30);
pq.push(10);
pq.push(20);

// Pop elements (highest priority first)


while (!pq.empty()) {
cout << pq.top() << " "; // Access the top element
pq.pop(); // Remove the top element
}
cout << endl;

return 0;
}

8. Iterators

Iterators are used to traverse containers.

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

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

// Use iterators to traverse the vector


for (auto it = numbers.begin(); it != numbers.end(); ++it) {
cout << *it << " ";
}
cout << endl;

return 0;
}

9. Functors

Functors are objects that behave like functions.

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

struct Square {
int operator()(int x) const {
return x * x;
}
};

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

// Apply a functor to each element


Square square;
transform(numbers.begin(), numbers.end(), numbers.begin(), square);

// Print squared numbers


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

return 0;
}

Best Practices for Using STL


1. Choose the Right Container: Select the container that best fits your needs (e.g.,
std::vector for dynamic arrays, std::map for key-value pairs).
2. Use Algorithms: Prefer STL algorithms over manual loops for common operations (e.g.,
sorting, searching).
3. Avoid Raw Loops: Use range-based for loops or algorithms to make code more readable.
4. Understand Iterator Types: Use the appropriate iterator type for your container (e.g.,
random access iterators for std::vector).
5. Use Functors and Lambdas: Leverage functors and lambda expressions for custom
behavior in algorithms

40. Standard Library

The C++ Standard Library is a collection of classes and functions that provide essential
functionality for C++ programs. It includes the Standard Template Library (STL),
input/output (I/O) facilities, string manipulation, mathematical functions, and more. Below is a
detailed tutorial on the key components of the C++ Standard Library.
Key Components of the C++ Standard Library
1. Containers: Data structures like vector, list, map, etc.
2. Algorithms: Functions like sort, find, copy, etc.
3. Iterators: Used to traverse containers.
4. Input/Output (I/O): Classes like cin, cout, ifstream, ofstream.
5. Strings: The std::string class for string manipulation.
6. Numerics: Mathematical functions and utilities.
7. Utilities: General-purpose utilities like std::pair, std::tuple, and std::function.
8. Smart Pointers: Memory management utilities like std::unique_ptr and std::shared_ptr.
9. Multithreading: Threading support with std::thread, std::mutex, etc.
10. Time Utilities: Time-related functions and classes like std::chrono.

1. Containers
Containers are data structures that store collections of objects. The most commonly used
containers are:

Sequence Containers

• std::vector: Dynamic array.


• std::list: Doubly linked list.
• std::deque: Double-ended queue.
• std::array: Fixed-size array (introduced in C++11).

Example: std::vector
#include <iostream>
#include <vector>
using namespace std;

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

// Add elements
numbers.push_back(6);

// Access elements
cout << "First element: " << numbers[0] << endl;

// Iterate using a range-based for loop


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

// Size of the vector


cout << "Size: " << numbers.size() << endl;
return 0;
}

Associative Containers

• std::set: Collection of unique keys.


• std::map: Collection of key-value pairs with unique keys.
• std::multiset: Collection of keys, allowing duplicates.
• std::multimap: Collection of key-value pairs, allowing duplicate keys.

Example: std::map
#include <iostream>
#include <map>
using namespace std;

int main() {
map<string, int> ages;

// Insert elements
ages["Alice"] = 25;
ages["Bob"] = 30;

// Access elements
cout << "Alice's age: " << ages["Alice"] << endl;

// Iterate using iterators


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

return 0;
}

Unordered Containers

• std::unordered_set: Hash-based set.


• std::unordered_map: Hash-based map.

Example: std::unordered_map
#include <iostream>
#include <unordered_map>
using namespace std;

int main() {
unordered_map<string, int> ages;

// Insert elements
ages["Alice"] = 25;
ages["Bob"] = 30;
// Access elements
cout << "Alice's age: " << ages["Alice"] << endl;

// Iterate using iterators


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

return 0;
}

2. Algorithms
STL provides a wide range of algorithms that operate on containers. These include:

• Sorting: std::sort, std::stable_sort


• Searching: std::find, std::binary_search
• Modifying: std::copy, std::transform
• Numeric: std::accumulate, std::inner_product

Example: std::sort
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

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

// Sort the vector


sort(numbers.begin(), numbers.end());

// Print sorted vector


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

return 0;
}

3. Input/Output (I/O)
The C++ Standard Library provides classes for input and output operations:

• std::cin: Standard input.


• std::cout: Standard output.
• std::ifstream: Input file stream.
• std::ofstream: Output file stream.

Example: File I/O


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

int main() {
// Write to a file
ofstream outFile("example.txt");
if (outFile.is_open()) {
outFile << "Hello, File!" << endl;
outFile.close();
}

// Read from a file


ifstream inFile("example.txt");
string line;
if (inFile.is_open()) {
while (getline(inFile, line)) {
cout << line << endl;
}
inFile.close();
}

return 0;
}

4. Strings
The std::string class provides powerful string manipulation capabilities.

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

int main() {
string str = "Hello, World!";

// Access characters
cout << "First character: " << str[0] << endl;

// Concatenate strings
string str2 = " How are you?";
string result = str + str2;
cout << result << endl;

// Find substring
size_t pos = str.find("World");
if (pos != string::npos) {
cout << "Found 'World' at position: " << pos << endl;
}

return 0;
}

5. Numerics
The C++ Standard Library provides mathematical functions and utilities.

Example: std::sqrt, std::pow


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

int main() {
double x = 16.0;
cout << "Square root of " << x << ": " << sqrt(x) << endl;
cout << "2^3: " << pow(2, 3) << endl;
return 0;
}

6. Utilities
The Standard Library includes general-purpose utilities like std::pair, std::tuple, and std::function.

Example: std::pair
#include <iostream>
#include <utility>
using namespace std;

int main() {
pair<string, int> person("Alice", 25);
cout << "Name: " << person.first << ", Age: " << person.second << endl;
return 0;
}

7. Smart Pointers
Smart pointers automate memory management and prevent memory leaks.

Example: std::unique_ptr
#include <iostream>
#include <memory>
using namespace std;

int main() {
unique_ptr<int> ptr(new int(42));
cout << "Value: " << *ptr << endl;
// No need to delete; memory is automatically released
return 0;
}

8. Multithreading
The Standard Library provides support for multithreading.

Example: std::thread
#include <iostream>
#include <thread>
using namespace std;

void task() {
cout << "Thread is running!" << endl;
}

int main() {
thread t1(task);
t1.join(); // Wait for the thread to finish
cout << "Main thread continues..." << endl;
return 0;
}

9. Time Utilities
The std::chrono library provides time-related utilities.

Example: std::chrono
#include <iostream>
#include <chrono>
#include <thread>
using namespace std;
using namespace std::chrono;

int main() {
auto start = high_resolution_clock::now();

// Simulate work
this_thread::sleep_for(seconds(2));

auto end = high_resolution_clock::now();


auto duration = duration_cast<milliseconds>(end - start);

cout << "Time taken: " << duration.count() << " milliseconds" << endl;
return 0;
}
Best Practices for Using the Standard Library
1. Use Containers Wisely: Choose the right container for your needs.
2. Leverage Algorithms: Use STL algorithms instead of writing manual loops.
3. Prefer Smart Pointers: Use std::unique_ptr and std::shared_ptr for memory management.
4. Use Standard Utilities: Take advantage of utilities like std::pair, std::tuple, and std::function.
5. Avoid Raw Pointers: Minimize the use of raw pointers to prevent memory leaks.

Additional Content (Incorporated)

Advantages and Disadvantages of OOP


• Advantage:
o Reusability: Code can be reused through inheritance, reducing redundancy.
• Disadvantage:
o Complexity: OOP can be more complex to design and implement, especially for
small programs.

Definitions
• Source Code: Human-readable code written in a high-level language.
• Object Code: Machine-readable code produced by a compiler.
• Class: A blueprint for creating objects.
• Object: An instance of a class.
• Function: A block of code that performs a specific task.

Using Directive
• Advantages:
o Simplifies code by avoiding std:: prefix.
• Disadvantages:
o Can lead to naming conflicts and reduced clarity.

Inheritance Benefits
1. Code Reusability: Reduces redundancy.
2. Extensibility: Add new features to derived classes.
3. Maintainability: Changes in the base class propagate to derived classes.

Function Encapsulation
• Encapsulation: Hides implementation details, making code modular and easier to debug.
Polymorphism
• Polymorphism: Allows objects of different classes to be treated as objects of a common
superclass, enabling flexible and reusable code.

Increment Operators
• Prefix (++i): Increments before use.
• Postfix (i++): Increments after use.

Friend Functions
• Friend Functions: Can access private and protected members of a class, potentially
undermining encapsulation.

Program Examples
• Pointer to Memory Address:
int num = 62;
int* ptr = &num;
cout << "Memory address: " << ptr;

• Sum of Even and Product of Odd Numbers:


int sumEven = 0;
long long productOdd = 1;
for (int i = 200; i <= 300; i++) {
if (i % 2 == 0) {
sumEven += i;
} else {
productOdd *= i;
}
}
cout << "Sum of even numbers: " << sumEven << endl;
cout << "Product of odd numbers: " << productOdd << endl;

Conclusion
This guide covers everything in C++ from the basics to advanced topics, including exam-style
questions and practical examples. Practice coding regularly and revise these concepts to ace
your exam. Good luck!

You might also like