C++ is a general-purpose, high-performance programming language developed as an extension of the C language by Bjarne Stroustrup at Bell Labs in 1979. It supports both procedural and object-oriented programming, making it a multi-paradigm language.
- Introduction
- Comments in C++
- Keywords in C++
- Escape sequences
- Variables
- Input and Output:
- Data Types
- Operators
- Control Flow
- Function
- String
- Array
- Pointers
- Object-Oriented Programming (OOP)
- Inheritance
- Polymorphism
- Encapsulation
- Abstraction
- Operator Overloading
- Templates and Generics
- Structure, Union and Enum
- Dynamic Memory Allocation
- Type Conversion and Typecasting
- File Handling
- Preprocessor Directives
- Error Handling
- Practice Problems and Projects
Recommended Tools:
- Editor: Visual Studio Code with the official C/C++ Extension
- IDE: Code::Blocks — preconfigured and suitable for beginners
- Online Compiler: CodeChef IDE — for quick practice and testing
- Compiled Language – Translates source code into machine code for faster execution.
- Object-Oriented – Supports classes, objects, inheritance, polymorphism, encapsulation, and abstraction.
- Low-Level Manipulation – Allows direct manipulation of memory using pointers.
- Rich Standard Library – Includes the Standard Template Library (STL) for data structures and algorithms.
- Portable – Write once, run anywhere (on systems with the same compiler).
- Fast Execution – Closer to hardware, C++ is often used in performance-critical applications.
- Foundation for understanding programming and computer science.
- Teaches memory management, performance tuning, and data structures.
- Used widely in industry and competitive programming.
- Game Development: Unreal Engine, game engines, physics simulations.
- System Programming: Operating systems, device drivers.
- Embedded Systems: Firmware for electronic devices.
- GUI Applications: Tools using Qt, wxWidgets
- Financial Systems: High-frequency trading, banking software.
- Compilers & Tools: GCC, LLVM
#include <iostream>
using namespace std;
int main() {
cout << "Hello, World!" << endl; // Output: Hello, World!
return 0;
}
In C++, comments are used to document code and improve its readability. Just like in C, comments are ignored by the compiler, so they do not affect how the program runs.
C++ supports two types of comments:
Use //
for single-line comments.
// This is a single-line comment
int x = 10; // This sets x to 10
Use /* */
for multi-line comments.
/* This is a multi-line comment
It can span multiple lines
*/
int y = 20;
Keywords are reserved words in C++ that have special, predefined meanings. These words form the syntax and structure of the language and cannot be used as identifiers (such as variable names, function names, or class names).
C++ inherits most of its keywords from C and introduces additional ones to support object-oriented programming, templates, exception handling, namespaces, and more.
No. | Keyword | No. | Keyword | No. | Keyword | No. | Keyword |
---|---|---|---|---|---|---|---|
1 | alignas |
17 | do |
33 | mutable |
49 | template |
2 | alignof |
18 | double |
34 | namespace |
50 | this |
3 | and |
19 | dynamic_cast |
35 | new |
51 | thread_local |
4 | and_eq |
20 | else |
36 | noexcept |
52 | throw |
5 | asm |
21 | enum |
37 | not |
53 | true |
6 | auto |
22 | explicit |
38 | not_eq |
54 | try |
7 | bitand |
23 | export |
39 | nullptr |
55 | typedef |
8 | bitor |
24 | extern |
40 | operator |
56 | typeid |
9 | bool |
25 | false |
41 | or |
57 | typename |
10 | break |
26 | float |
42 | or_eq |
58 | union |
11 | case |
27 | for |
43 | private |
59 | unsigned |
12 | catch |
28 | friend |
44 | protected |
60 | using |
13 | char |
29 | goto |
45 | public |
61 | virtual |
14 | class |
30 | if |
46 | register |
62 | void |
15 | compl |
31 | inline |
47 | reinterpret_cast |
63 | volatile |
16 | const |
32 | int |
48 | return |
64 | wchar_t |
Note
- Some older keywords (like
register
,goto
,volatile
) are rarely used in modern C++ code. - Meanwhile, keywords like
auto
,nullptr
,constexpr
,decltype
, andtemplate
are heavily used in modern C++.
Escape sequences (also called backslash character constants) are special character combinations starting with a backslash (\
). They are used to represent characters that either can't be typed directly or perform special actions in strings and characters.
They are essential in text formatting, output control, and special character representation.
Escape Sequence | Meaning | Example in Code | Output: |
---|---|---|---|
\n |
New line | cout << "Hello\nWorld"; |
Hello World |
\t |
Horizontal tab | cout << "Hello\tWorld"; |
Hello World |
\b |
Backspace | cout << "Helloo\b!"; |
Hello! |
\r |
Carriage return | cout << "Hello\rWorld"; |
World |
\f |
Form feed (page break) | Rarely used | — |
\a |
Alert (bell sound) | cout << "\a"; |
🔔 (beep sound) |
\\ |
Backslash | cout << "\\"; |
\ |
\' |
Single quote | cout << "\'"; |
' |
\" |
Double quote | cout << "\""; |
" |
\? |
Question mark | cout << "\?"; |
? |
\0 |
Null character (end of string) | Used in character arrays | — |
\ooo |
Octal number (e.g., \141 = 'a') |
cout << "\141"; |
a |
\xhh |
Hexadecimal (e.g., \x61 = 'a') |
cout << "\x61"; |
a |
Example:
#include <iostream>
using namespace std;
int main() {
cout << "Line1\nLine2\n"; // newline
cout << "Tab\tSpace\n"; // tab
cout << "Backslash: \\\n"; // backslash
cout << "Quote: \' \" \n"; // single and double quotes
cout << "Beep\a\n"; // beep sound (if supported)
return 0;
}
Note
-
Escape sequences are used in both character literals (
'\n'
) and string literals ("\n"
). -
They are crucial for:
- Formatting output
- Representing invisible/special characters
- Handling control characters in streams
-
Some escape sequences (
\a
,\f
, etc.) may not have visible effects in all modern terminal environments.
A variable in C++ is a named memory location used to store data that can be modified during program execution.
- Acts as a storage unit for data.
- Must be declared with a data type before use.
- Its value can be changed at any time during execution.
Syntax:
<data_type> <variable_name>;
<data_type> <variable_name> = value;
Example:
#include <iostream>
using namespace std;
int main() {
int age; // Declaration
age = 25; // Assignment
float pi = 3.14; // Declaration + Assignment
cout << "Age: " << age << endl;
cout << "Pi: " << pi << endl;
return 0;
}
Output:
Age: 25
Pi: 3.14
Rule No. | Rule |
---|---|
1 | Must begin with a letter (A–Z or a–z) or underscore _ |
2 | Can include letters, digits (0–9), and underscores |
3 | Cannot start with a digit |
4 | Cannot use C++ keywords (like int , return , etc.) |
5 | Case-sensitive (Age and age are different) |
6 | Should be meaningful (use descriptive names) |
Type | Description | Scope |
---|---|---|
Local | Declared inside a function/block | Function/block |
Global | Declared outside all functions, accessible by all functions | Whole program |
Static | Retains value between function calls, has local scope | Block/function |
Extern | Declared in one file, defined in another (shared globally) | Global |
Register | Suggests storing variable in a CPU register (faster access) | Local |
Example: (Variable Types)
#include <iostream>
using namespace std;
int globalVar = 10; // Global variable
void function() {
static int staticVar = 0; // Static variable
staticVar++;
cout << "Static: " << staticVar << endl;
}
int main() {
int localVar = 5; // Local variable
cout << "Global: " << globalVar << endl;
cout << "Local: " << localVar << endl;
function();
function();
return 0;
}
Output:
Global: 10
Local: 5
Static: 1
Static: 2
✅ Good Practice Example
int studentAge = 20;
float temperature = 36.6;
char grade = 'A';
Feature | Variable | Constant |
---|---|---|
Value change | Can change during execution | Cannot change once assigned |
Declaration | int age = 20; |
const int age = 20; |
Tip
- Variables store values in RAM.
- Use const for read-only values.
- Always initialize variables to avoid garbage values.
- Use descriptive names to improve code readability.
C++ uses standard input/output objects provided by the iostream
header for communication between the user and the program.
#include <iostream>
💡 You must include this header to use cin, cout, and other standard I/O utilities.
cout
is used for output to the console. It uses the insertion operator (<<
).
Syntax:
cout << "text" << variable;
Example:
#include <iostream>
using namespace std;
int main() {
int age = 20;
cout << "Age is " << age << endl;
return 0;
}
Output:
Age is 20
cin
is used to read input from the user. It uses the extraction operator (>>
).
Syntax:
cin >> variable;
Example:
#include <iostream>
using namespace std;
int main() {
int age;
cout << "Enter your age: ";
cin >> age;
cout << "You entered: " << age << endl;
return 0;
}
Output: (sample interaction)
Enter your age: 25
You entered: 25
Unlike C, C++ does not use format specifiers like %d
, %f
. It handles type safety with stream objects (cin
, cout
).
Example: Input and Output:
#include <iostream>
#include <string>
using namespace std;
int main() {
int age;
float salary;
char initial;
string name;
// Input
cout << "Enter your age: ";
cin >> age;
cout << "Enter your salary: ";
cin >> salary;
cout << "Enter your first initial: ";
cin >> initial;
cout << "Enter your name: ";
cin >> name; // string input (single word only)
// Output:
cout << "\n--- OUTPUT ---\n";
cout << "Age: " << age << endl;
cout << "Salary: " << salary << endl;
cout << "Initial: " << initial << endl;
cout << "Name: " << name << endl;
return 0;
}
Output:
Enter your age: 25
Enter your salary: 65000.5
Enter your first initial: M
Enter your name: Alice
--- OUTPUT ---
Age: 25
Salary: 65000.5
Initial: M
Name: Alice
Use getline(cin, str)
to accept entire lines with spaces.
Example: getline()
#include <iostream>
#include <string>
using namespace std;
int main() {
string fullName;
cout << "Enter your full name: ";
getline(cin, fullName);
cout << "Hello, " << fullName << "!" << endl;
return 0;
}
Output:
Enter your full name: John Smith
Hello, John Smith!
Function | Purpose | Notes |
---|---|---|
cin |
Read input (no format needed) | Safe and type-checked |
cout |
Output: to console | Uses << operator |
getline() |
Read full line including spaces | Safer for strings |
cerr |
Output: error messages | Unbuffered |
clog |
Output: error/info messages | Buffered |
Note
- Use
getline()
to handle strings with spaces. cin
ignores leading whitespace, butgetline()
does not.cin >>
stops at the first whitespace character.cout
automatically formats values (no need for%d
,%f
, etc.).
Data types in C++ specify the kind of data a variable can store. C++ supports both primitive and user-defined types. Unlike C, C++ uses type-safe I/O operations with cin
and cout
, so there are no format specifiers.
Data Type | Description | Size (Typical) | Range |
---|---|---|---|
char |
Stores a single character | 1 byte | -128 to 127 (signed) or 0 to 255 (unsigned) |
int |
Stores integer values | 4 bytes | -2,147,483,648 to 2,147,483,647 |
float |
Single-precision floating point number | 4 bytes | ±3.4E±38 (approx.) |
double |
Double-precision floating point number | 8 bytes | ±1.7E±308 (approx.) |
void |
Represents absence of type (e.g., return) | 0 bytes | N/A |
Type | Description |
---|---|
array |
Collection of elements of the same type |
pointer |
Stores memory address of another variable |
struct |
Groups variables of different types together |
union |
Shares memory among multiple variables |
enum |
User-defined type with named constants (usually integers) |
Modifier | Effect |
---|---|
signed |
Allows negative and positive values (default for int and char ) |
unsigned |
Only positive values, larger upper bound |
long |
Extends the range of int or double |
short |
Reduces the size of int , saves memory |
Example: Using Various Data Types
#include <iostream>
using namespace std;
int main() {
char letter = 'A';
int num = 100;
float pi = 3.14f;
double precisePi = 3.1415926535;
unsigned int uNum = 250;
long long bigNum = 1234567890123;
short smallNum = 10;
int* ptr = #
// Output: without format specifiers
cout << "Character: " << letter << endl;
cout << "Integer: " << num << endl;
cout << "Float: " << pi << endl;
cout << "Double: " << precisePi << endl;
cout << "Unsigned Int: " << uNum << endl;
cout << "Long Long: " << bigNum << endl;
cout << "Short: " << smallNum << endl;
cout << "Pointer (address of num): " << ptr << endl;
return 0;
}
Output:
Character: A
Integer: 100
Float: 3.14
Double: 3.14159
Unsigned Int: 250
Long Long: 1234567890123
Short: 10
Pointer (address of num): 0x7ffeeef4b7dc
C++ does not use format specifiers like %d
, %f
, etc. Instead:
cin >> var;
andcout << var;
work with the variable's type.- It’s type-safe, unlike C's
printf()
/scanf()
which rely on specifiers.
Use C++ I/O manipulators like std::fixed
, std::setprecision
, std::setw
, etc. from <iomanip>
.
Example: Precision Formatting
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
double num = 3.14159265;
cout << "Default: " << num << endl;
cout << "Fixed with 2 decimal places: " << fixed << setprecision(2) << num << endl;
return 0;
}
Output:
Default: 3.14159
Fixed with 2 decimal places: 3.14
Note
- C++ removes the need for format specifiers by overloading
<<
and>>
. - Type safety makes input/output less error-prone than C.
- You can still use
printf()
andscanf()
in C++, but it's discouraged in modern practice.
Operators in C++ are symbols used to perform operations on variables and values.
Types of Operators:
Used for mathematical operations.
Operator | Meaning | Example | Result |
---|---|---|---|
+ |
Addition | a + b |
10 + 5 = 15 |
- |
Subtraction | a - b |
10 - 5 = 5 |
* |
Multiplication | a * b |
10 * 5 = 50 |
/ |
Division | a / b |
10 / 5 = 2 |
% |
Modulus (remainder) | a % b |
10 % 3 = 1 |
Used to compare two values.
Operator | Meaning | Example | Result |
---|---|---|---|
== |
Equal to | a == b |
false (0) |
!= |
Not equal to | a != b |
true (1) |
> |
Greater than | a > b |
true (1) |
< |
Less than | a < b |
false (0) |
>= |
Greater or equal | a >= b |
true (1) |
<= |
Less or equal | a <= b |
false (0) |
Used to combine multiple conditions.
Operator | Meaning | Example | Result |
---|---|---|---|
&& |
Logical AND | a > 5 && b < 10 |
true if both true |
┃┃ |
Logical OR | a > 5 ┃┃ b < 10 |
true if any one true |
! |
Logical NOT | !(a > 5) |
reverses result |
Used to assign values.
Operator | Meaning | Example | Equivalent To |
---|---|---|---|
= |
Assign | a = 10 |
— |
+= |
Add and assign | a += 5 |
a = a + 5 |
-= |
Subtract and assign | a -= 5 |
a = a - 5 |
*= |
Multiply and assign | a *= 2 |
a = a * 2 |
/= |
Divide and assign | a /= 2 |
a = a / 2 |
%= |
Modulus and assign | a %= 3 |
a = a % 3 |
Increase or decrease a value by 1.
Operator | Meaning | Example | Description |
---|---|---|---|
++ |
Increment | a++ |
Post-increment (use then add) |
-- |
Decrement | --a |
Pre-decrement (subtract then use) |
Operate on binary digits.
Operator | Meaning | Example |
---|---|---|
& |
AND | a & b |
┃ |
OR | a ┃ b |
^ |
XOR | a ^ b |
~ |
NOT | ~a |
<< |
Left shift | a << 1 |
>> |
Right shift | a >> 1 |
Condition:
- Work with bit/byte
- Work into only integer number
Operation Steps:
1. First, convert the decimal or integer number to a binary number.
Example:
let, int x=32, y=12; 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 (from: 2^n)
-----------------------------------
Convert to Binary, x=32= 0 0 1 0 0 0 0 0
Convert to Binary, y=12= 0 0 0 0 1 1 0 0
2. Operation:
Bitwise AND: &
Condition: If Both input are '1' then out: 1. Otherwise; out: 0
Binary, x=32= 0 0 1 0 0 0 0 0
Binary, y=12= 0 0 0 0 1 1 0 0
--------------------------------
Multiply[x*y]= 0 0 0 0 0 0 0 0 (= result: 0)
Bitwise OR: |
Condition: If Both/Any input are '1' then out: 1. Otherwise; out: 0
Binary, x=32= 0 0 1 0 0 0 0 0
Binary, y=12= 0 0 0 0 1 1 0 0
---------------------------------
Addition[x+y]= 0 0 1 0 1 1 0 0 (= result: 44)
Bitwise EX-OR: ^
Condition: If Both input are same then out: 0. Otherwise; out: 1
Binary, x=32= 0 0 1 0 0 0 0 0
Binary, y=12= 0 0 0 0 1 1 0 0
---------------------------------
Ex-OR [x^y] = 0 0 1 0 1 1 0 0 (= result: 44)
A shorthand for if-else
.
condition ? expression_if_true : expression_if_false;
Example:
int a = 10, b = 20;
int max = (a > b) ? a : b;
cout << "Max: " << max << endl; // Output: 20
Returns the size (in bytes) of a variable or type.
Example:
cout << sizeof(int); // Output: 4 (usually)
Evaluates multiple expressions, returns the last.
Example:
int x = (a = 5, b = 10); // x = 10
Used for pointer operations.
Operator | Meaning | Example |
---|---|---|
* |
Dereference | *ptr |
& |
Address-of | &var |
🟢🔵🟣 Complete Example:
#include <iostream>
using namespace std;
int main() {
int a = 5, b = 2;
cout << "Addition: " << a + b << endl;
cout << "Greater? " << (a > b) << endl;
cout << "Logical AND: " << ((a > 0) && (b > 0)) << endl;
cout << "Bitwise AND: " << (a & b) << endl;
cout << "Ternary Max: " << ((a > b) ? a : b) << endl;
return 0;
}
Output:
Addition: 7
Greater? 1
Logical AND: 1
Bitwise AND: 0
Ternary Max: 5
Control structures in C++ determine the flow of execution of the program — which blocks of code get executed and when.
Types of Control Structures:
- Conditional Statements (Decision-making)
- Looping Statements (Iteration)
- Jump Statements (Branching)
Used to execute code based on conditions.
if (condition) {
// code to execute if condition is true
}
Example:
#include <iostream>
using namespace std;
int main() {
int number = 10;
if (number > 0) {
cout << "The number is positive." << endl;
}
return 0;
}
Output:
The number is positive.
if (condition) {
// if true
} else {
// if false
}
Example:
#include <iostream>
using namespace std;
int main() {
int number = 10;
if (number > 0) {
cout << "The number is positive." << endl;
} else {
cout << "The number is not positive." << endl;
}
return 0;
}
Output:
The number is positive.
if (condition1) {
// block 1
} else if (condition2) {
// block 2
} else {
// default block
}
Example:
#include <iostream>
using namespace std;
int main() {
int number = 0;
if (number > 0) {
cout << "The number is positive." << endl;
} else if (number < 0) {
cout << "The number is negative." << endl;
} else {
cout << "The number is zero." << endl;
}
return 0;
}
Output:
The number is zero.
if (condition1) {
if (condition2) {
// block
}
}
Example:
#include <iostream>
using namespace std;
int main() {
int number = 25;
if (number > 0) {
if (number < 100) {
cout << "Number is positive and less than 100." << endl;
}
}
return 0;
}
Output:
Number is positive and less than 100.
Used for multiple constant values.
switch (expression) {
case constant1:
// code
break;
case constant2:
// code
break;
default:
// default code (Optional)
}
Example:
#include <iostream>
using namespace std;
int main() {
int day = 3;
switch (day) {
case 1:
cout << "Saturday" << endl;
break;
case 2:
cout << "Sunday" << endl;
break;
case 3:
cout << "Monday" << endl; // this block is activated
break;
case 4:
cout << "Tuesday" << endl;
break;
case 5:
cout << "Wednesday" << endl;
break;
case 6:
cout << "Thursday" << endl;
break;
case 7:
cout << "Friday" << endl;
break;
default:
cout << "Invalid day" << endl;
break;
}
return 0;
}
Output:
Monday
Used to repeat a block of code multiple times.
for (initialization; condition; increment) {
// code block
}
Example:
#include <iostream>
using namespace std;
int main() {
// Print numbers from 1 to 5
for (int i = 1; i <= 5; i++) {
cout << i << " ";
}
return 0;
}
Output:
1 2 3 4 5
while (condition) {
// code block
}
Example:
#include <iostream>
using namespace std;
int main() {
int i = 1;
// Print numbers from 1 to 5
while (i <= 5) {
cout << i << " ";
i++; // increment i
}
return 0;
}
Output:
1 2 3 4 5
do {
// code block
} while (condition);
💡 Executes at least once even if the condition is false.
Example:
#include <iostream>
using namespace std;
int main() {
int i = 1;
// Print numbers from 1 to 5 using do-while loop
do {
cout << i << " ";
i++; // increment i
} while (i <= 5);
return 0;
}
Output:
1 2 3 4 5
Feature | while Loop |
do-while Loop |
---|---|---|
Condition check | Before loop body | After loop body |
Minimum executions | 0 | 1 |
Use cases | When you're unsure if the loop should execute at least once | When you want the loop to execute at least once, regardless of the condition |
Used to control the flow of loops and functions.
Keyword | Description |
---|---|
break |
Exits loop or switch block |
continue |
Skips the rest of the loop for the current iteration |
goto |
Jumps to a labeled part of the program ( |
return |
Exits from a function |
#include <iostream>
using namespace std;
int main() {
for (int i = 1; i <= 10; i++) {
if (i == 5)
break;
cout << i << " ";
}
return 0;
}
Output:
1 2 3 4
#include <iostream>
using namespace std;
int main() {
for (int i = 1; i <= 5; i++) {
if (i == 3)
continue;
cout << i << " ";
}
return 0;
}
Output:
1 2 4 5
Example (goto):
#include <iostream>
using namespace std;
int main() {
int num;
start:
cout << "Enter a positive number: ";
cin >> num;
if (num < 0) {
cout << "Negative number entered. Try again.\n";
goto start; // jump to start label
}
cout << "You entered: " << num << endl;
return 0;
}
Output:
Enter a positive number: -5
Negative number entered. Try again.
Enter a positive number: 10
You entered: 10
A function in C++ is a block of code that performs a specific task. It helps in organizing code, avoiding repetition, and improving reusability.
Real-life analogy to understand function:
A function in C++ is like a coffee machine — you press a button (input), it brews coffee (process), and gives you a cup (output).
Types of Functions
- User-defined Functions: Created by the programmer.
- Built-in (Library) Functions: Provided by C++ standard libraries.
Syntax (Declaration + Definition + Call):
// ❏ Function Declaration
returnType functionName(dataType1 parameter1, dataType2 parameter2, ...);
// ❏ Function Definition
returnType functionName(dataType1 parameter1, dataType2 parameter2, ...) {
// code block
return value; // If the function returns a value
}
// ❏ Function Call
functionName(arguments);
The Function Components are -
- Function Declaration
- Function Definition
- Function Call
Function Declaration:
It tells the compiler about the function's name, return type, and parameters — before it is used.
int add(int a, int b); // Declaration
- Return type:
int
- Function name:
add
- Parameters:
int a, int b
💡 Think of this as informing the compiler: "Hey! I’ll use a function like this later."
Function Definition:
Contains the actual code (body) that runs when the function is called.
int add(int a, int b) {
return a + b;
}
- This is where the logic of addition is implemented.
Function Call:
Used to invoke/execute the function and get the result.
int result = add(3, 5); // Function call
- Passes arguments
3
and5
to the function. - Stores the returned value in
result
.
Full Example with All Components
#include <iostream>
using namespace std;
// 1. Function Declaration
int add(int a, int b);
int main() {
// 3. Function Call
int sum = add(10, 20);
cout << "Sum = " << sum << endl;
return 0;
}
// 2. Function Definition
int add(int a, int b) {
return a + b;
}
Output:
Sum = 30
Example (No return, no parameters):
#include <iostream>
using namespace std;
void greet() {
cout << "Hello, World!" << endl;
}
int main() {
greet();
return 0;
}
Output:
Hello, World!
Example (With return, with parameters):
#include <iostream>
using namespace std;
int add(int a, int b) {
return a + b;
}
int main() {
int sum = add(4, 5);
cout << "Sum = " << sum << endl;
return 0;
}
Output:
Sum = 9
Example (Function Declaration (Prototype)):
#include <iostream>
using namespace std;
int multiply(int, int); // function declaration
int main() {
cout << "Result = " << multiply(3, 4) << endl;
return 0;
}
int multiply(int x, int y) {
return x * y;
}
Output:
Result = 12
A recursive function is a function that calls itself to solve smaller versions of a problem.
Real-life analogy to understand recursion:
Like opening a set of nested boxes — each box opens the next, until the smallest box is reached.
Example:
#include <iostream>
using namespace std;
int factorial(int n) {
if (n == 0) return 1;
return n * factorial(n - 1);
}
int main() {
cout << "Factorial of 5 = " << factorial(5) << endl;
return 0;
}
Output:
Factorial of 5 = 120
Return Types in C++ Functions:
Return Type | Meaning | Example |
---|---|---|
void |
No return value | void show() |
int |
Returns integer | int getSum() |
float |
Returns float value | float avg() |
char |
Returns a character | char getGrade() |
Parameter Types:
Type | Example | Description |
---|---|---|
No Parameters | void greet(void) |
Takes no input |
With Parameters | int sum(int a, int b) |
Takes input values |
Default (Not in C++) | ❌ | C++ doesn’t support default params |
Variable Arguments | int printf(...) |
Use stdarg.h |
Function Categories:
Function Type | Parameters | Return Value | Example |
---|---|---|---|
No Parameters, No Return | No | No | void greet(void) |
With Parameters, No Return | Yes | No | void greet(char name[]) |
No Parameters, With Return | No | Yes | int getTime(void) |
With Parameters and Return | Yes | Yes | int add(int a, int b) |
These are pre-defined functions provided by C++'s standard library.
Example: cout
, cin
, strlen()
, malloc()
, etc.
Header Files:
You don't need to define these functions, but you must include the appropriate header files. Some Common Header Files:
-
<iostream>
: For input-output.- Includes:
cout
,cin
,endl
- Includes:
-
<cmath>
: For mathematical functions.- Includes:
sqrt()
,pow()
,sin()
,cos()
,tan()
- Includes:
-
<cstring>
: For string manipulation.- Includes:
strlen()
,strcpy()
,strcmp()
,strcat()
- Includes:
Example: sizeof()
#include <iostream>
using namespace std;
int main() {
char a;
int b;
float c;
double d;
cout << "Size of Character is: " << sizeof(a) << " bytes" << endl;
cout << "Size of Integer is: " << sizeof(b) << " bytes" << endl;
cout << "Size of Float is: " << sizeof(c) << " bytes" << endl;
cout << "Size of Double is: " << sizeof(d) << " bytes" << endl;
return 0;
}
Output:
Size of Character is: 1 bytes
Size of Integer is: 4 bytes
Size of Float is: 4 bytes
Size of Double is: 8 bytes
Example (String): strlen()
#include <iostream>
#include <cstring>
using namespace std;
int main() {
char name[] = "Nazrull";
int len = strlen(name);
cout << "Length: " << len << endl;
return 0;
}
Output:
Length: 7
Example (Random Number Generator): rand()
#include <iostream>
#include <cstdlib> // Using header file for random numbers
using namespace std;
int main() {
for (int i = 1; i <= 5; i++) {
int randomNum = rand(); // Random numbers generator
cout << "Random Number: " << randomNum << endl;
}
return 0;
}
Output:
Random Number 1: 1804289383
Random Number 2: 846930886
Random Number 3: 1681692777
💡 Note: Output: will vary every time if seeded using srand(time(0));
Example (String Concatenation): strcat()
#include <iostream>
#include <cstring>
using namespace std;
int main() {
char name1[20] = "Michael ";
char name2[] = "Scofield";
strcat(name1, name2);
cout << "Concatenated Name: " << name1 << endl;
return 0;
}
Output:
Concatenated Name: Michael Scofield
Example (String Comparison): strcmp()
#include <iostream>
#include <cstring>
using namespace std;
int main() {
char name1[] = "Michael";
char name2[] = "Scofield";
int result = strcmp(name1, name2);
if (result == 0)
cout << "Strings are equal" << endl;
else
cout << "Strings aren't equal" << endl;
return 0;
}
Output:
Strings aren't equal
Example (Mathematical Operations)
abs()
, sqrt()
, pow()
, log()
etc., are similarly available in the <cmath>
header for mathematical operations.
This C++ version preserves the same functionality and syntax from the C code, but uses C++-specific libraries like <iostream>
for input/output and <cstring>
for string manipulations.
In programming, a string is a sequence of characters used to represent text.
In C++, we can work with two types of strings:
- C-style strings – like in C, implemented as character arrays ending with
'\0'
. - C++
std::string
– part of the C++ Standard Library, safer and easier to use.
Declaration:
char str[10]; // Can store up to 9 characters + null terminator '\0'
Using String Literal
char str[] = "Hello";
Automatically appends '\0'
at the end.
Using Character Array
char str[] = {'H', 'e', 'l', 'l', 'o', '\0'};
Example: Basic C-style String Input and Output:
#include <iostream>
using namespace std;
int main() {
char name[20];
cout << "Enter your name: ";
cin >> name; // Reads until first space
cout << "Hello, " << name << "!" << endl;
return 0;
}
Output:
Enter your name: Alice
Hello, Alice!
Example: Using cin.getline()
for Full Line Input
#include <iostream>
using namespace std;
int main() {
char fullName[50];
cout << "Enter your full name: ";
cin.getline(fullName, 50); // Safe input with spaces
cout << "Your name is: " << fullName << endl;
return 0;
}
Output:
Enter your full name: Alice Johnson
Your name is: Alice Johnson
Declaration and Initialization
#include <iostream>
#include <string>
using namespace std;
int main() {
string name = "Hello";
cout << name << endl;
return 0;
}
Example: String Input and Output: Using std::string
#include <iostream>
#include <string>
using namespace std;
int main() {
string name;
cout << "Enter your name: ";
cin >> name; // Reads a single word
cout << "Hello, " << name << "!" << endl;
return 0;
}
Output:
Enter your name: Alice
Hello, Alice!
Example: Full Line Input Using getline()
#include <iostream>
#include <string>
using namespace std;
int main() {
string fullName;
cout << "Enter your full name: ";
getline(cin, fullName); // Reads full line including spaces
cout << "Hello, " << fullName << "!" << endl;
return 0;
}
Output:
Enter your full name: Alice Johnson
Hello, Alice Johnson!
For C-style strings (<cstring>
) functions
Function | Description | Example |
---|---|---|
strlen(s) |
Returns length | strlen("Hi") → 2 |
strcpy(d, s) |
Copies string s to d |
strcpy(dest, src) |
strcat(d, s) |
Concatenates s to d |
strcat(dest, src) |
strcmp(s1,s2) |
Compares two strings | strcmp("abc", "abc") → 0 |
strrev(s) |
Reverses a string (non-standard) | strrev("abc") → "cba" |
For std::string
(more powerful)
Operation | Example | Output: |
---|---|---|
Length | name.length() |
Length of string |
Concatenation | s1 + s2 |
Combines strings |
Comparison | s1 == s2 |
true/false |
Access character | name[0] |
First letter |
Substring | name.substr(0, 5) |
Partial string |
Find substring | name.find("John") |
Index or npos |
Replace substring | name.replace(0, 5, "Hi") |
Replace part |
An array in C++ is a collection of elements of the same data type stored in contiguous memory locations.
Real-life analogy:
An array is like a bookshelf. Each shelf (array index) holds one book (element), and you can access any book by its position (index).
Syntax:
data_type array_name[array_size];
data_type
: Type of elements (e.g.,int
,float
,char
)array_name
: Name of the arrayarray_size
: Number of elements
Example:
#include <iostream>
using namespace std;
int main() {
int numbers[5] = {10, 20, 30, 40, 50};
cout << "First number: " << numbers[0] << endl;
cout << "Third number: " << numbers[2] << endl;
return 0;
}
Output:
First number: 10
Third number: 30
Array Declaration, Initialization & Access
// Array Declaration, Initialization
int numbers[5] = {10, 20, 30, 40, 50};
// Array Access
cout << numbers[0]; // Output: 10
cout << numbers[2]; // Output: 30
Array Accessing Diagram:
Index: 0 1 2 3 4
Value: 10 20 30 40 50
↑ ↑
numbers[0] numbers[2]
Types of Arrays in C++
-
Linear / 1D Arrays
-
Multi-Dimensional:
- 2D Array (Matrix)
- 3D Array
#include <iostream>
using namespace std;
int main() {
int numbers[5] = {10, 20, 30, 40, 50};
for (int i = 0; i < 5; i++) {
cout << numbers[i] << " ";
}
return 0;
}
Output:
10 20 30 40 50
#include <iostream>
using namespace std;
int main() {
int matrix[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
int element = matrix[1][2]; // 2nd row, 3rd col
cout << "Access Single Element: " << element << endl << endl;
cout << "Matrix Elements:" << endl;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
cout << matrix[i][j] << " ";
}
cout << endl;
}
return 0;
}
Output:
Access Single Element: 7
Matrix Elements:
1 2 3 4
5 6 7 8
9 10 11 12
#include <iostream>
using namespace std;
int main() {
int arr[2][3][4] = {
{
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
},
{
{13, 14, 15, 16},
{17, 18, 19, 20},
{21, 22, 23, 24}
}
};
cout << "Access Single Element: " << arr[1][2][3] << endl << endl;
for (int i = 0; i < 2; i++) {
cout << "Plane " << i << ":" << endl;
for (int j = 0; j < 3; j++) {
for (int k = 0; k < 4; k++) {
cout << arr[i][j][k] << " ";
}
cout << endl;
}
cout << endl;
}
return 0;
}
Output:
Access Single Element: 24
Plane 0:
1 2 3 4
5 6 7 8
9 10 11 12
Plane 1:
13 14 15 16
17 18 19 20
21 22 23 24
Method | Syntax Example |
---|---|
Full initialization | int arr[3] = {1, 2, 3}; |
Partial initialization | int arr[3] = {1}; // {1, 0, 0} |
Zero initialization | int arr[3] = {0}; |
Size inferred | int arr[] = {1, 2, 3, 4}; |
Example: Input from User
#include <iostream>
using namespace std;
int main() {
int a[5];
cout << "Enter 5 numbers: ";
for (int i = 0; i < 5; i++) {
cin >> a[i];
}
cout << "You entered: ";
for (int i = 0; i < 5; i++) {
cout << a[i] << " ";
}
return 0;
}
Output: (if input = 1 2 3 4 5):
Enter 5 numbers: You entered: 1 2 3 4 5
Example: Modifying Array Elements
#include <iostream>
using namespace std;
int main() {
int arr[5] = {5, 10, 15, 20, 25};
// Print original array
cout << "Original Array: ";
for (int i = 0; i < 5; i++) {
cout << arr[i] << " ";
}
cout << endl;
// Modify elements
arr[0] = 100; // change first element
arr[3] = 400; // change fourth element
// Print modified array
cout << "Modified Array: ";
for (int i = 0; i < 5; i++) {
cout << arr[i] << " ";
}
cout << endl;
return 0;
}
Output:
Original Array: 5 10 15 20 25
Modified Array: 100 10 15 400 25
Example: Sum of Array Elements
#include <iostream>
using namespace std;
int main() {
int a[5] = {1, 2, 3, 4, 5};
int sum = 0;
for (int i = 0; i < 5; i++) {
sum += a[i];
}
cout << "Sum = " << sum << endl;
return 0;
}
Output:
Sum = 15
Example: Passing Arrays to Functions
#include <iostream>
using namespace std;
void displayArray(int arr[], int size) {
for (int i = 0; i < size; i++) {
cout << arr[i] << " ";
}
cout << endl;
}
int main() {
int nums[] = {10, 20, 30, 40, 50};
int length = sizeof(nums) / sizeof(nums[0]);
cout << "Array elements: ";
displayArray(nums, length);
return 0;
}
Output:
Array elements: 10 20 30 40 50
Example: Array of Pointers
#include <iostream>
using namespace std;
int main() {
int numbers[] = {10, 20, 30, 40, 50};
int* ptrs[5];
for (int i = 0; i < 5; i++) {
ptrs[i] = &numbers[i];
}
for (int i = 0; i < 5; i++) {
cout << "Element " << i + 1 << ": " << *ptrs[i] << endl;
}
return 0;
}
Output:
Element 1: 10
Element 2: 20
Element 3: 30
Element 4: 40
Element 5: 50
Example: 2D Array of Pointers
#include <iostream>
using namespace std;
int main() {
int numbers[3][4] = {{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}};
int* ptrs[3][4];
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
ptrs[i][j] = &numbers[i][j];
}
}
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
cout << "Element [" << i << "][" << j << "]: " << *ptrs[i][j] << endl;
}
}
return 0;
}
Output:
Element [0][0]: 1
Element [0][1]: 2
...
Element [2][3]: 12
A pointer is a variable that stores the memory address of another variable.
Syntax:
data_type *pointer_name;
data_type
— type of data the pointer points to*
— denotes it’s a pointerpointer_name
— name of the pointer variable
Example (Declarations):
int *ptrInt; // Pointer to int
char *ptrChar; // Pointer to char
float *ptrFloat; // Pointer to float
You can assign the address of a variable using the address-of operator (&
).
Example:
#include <iostream>
using namespace std;
int main() {
int a = 10;
int *p;
p = &a;
cout << "Value of a: " << a << endl;
cout << "Address of a: " << &a << endl;
cout << "Pointer p stores address: " << p << endl;
cout << "Value pointed by p (*p): " << *p << endl;
return 0;
}
Output:
Value of a: 10
Address of a: 0x7ffee8e73abc // (Actual output may vary)
Pointer p stores address: 0x7ffee8e73abc
Value pointed by p (*p): 10
You can access or modify values using the dereference operator (*
).
Example:
#include <iostream>
using namespace std;
int main() {
int a = 10;
int *p = &a;
cout << "Value of a: " << a << endl;
cout << "Value of a via pointer: " << *p << endl;
*p = 20; // Modify a via pointer
cout << "New value of a: " << a << endl;
return 0;
}
Output:
Value of a: 10
Value of a via pointer: 10
New value of a: 20
Pointers can be incremented or decremented to move between elements in arrays.
Example:
#include <iostream>
using namespace std;
int main() {
int arr[] = {10, 20, 30, 40, 50};
int *p = arr;
cout << *p << endl;
p++; // Move to next element
cout << *p << endl;
return 0;
}
Output:
10
20
In C++, array names act like pointers to their first elements.
Example:
#include <iostream>
using namespace std;
int main() {
int arr[5] = {10, 20, 30, 40, 50};
int *p = arr;
for (int i = 0; i < 5; i++) {
cout << "Element " << i << ": " << *(p + i) << endl;
}
return 0;
}
Output:
Element 0: 10
Element 1: 20
Element 2: 30
Element 3: 40
Element 4: 50
You can create a pointer to another pointer, i.e., a pointer to pointer.
Example:
#include <iostream>
using namespace std;
int main() {
int a = 10;
int *p = &a;
int **pp = &p;
cout << "Value of a: " << **pp << endl;
return 0;
}
Output:
Value of a: 10
C++ uses new
and delete
for dynamic memory, unlike malloc
/free
in C.
Example:
#include <iostream>
using namespace std;
int main() {
int *p = new int[5]; // Allocate memory for 5 integers
for (int i = 0; i < 5; i++) {
p[i] = i * 10;
}
for (int i = 0; i < 5; i++) {
cout << p[i] << " ";
}
cout << endl;
delete[] p; // Free memory
return 0;
}
Output:
0 10 20 30 40
Function pointers allow calling functions dynamically or passing them as arguments.
Example:
#include <iostream>
using namespace std;
void display(int n) {
cout << "Number: " << n << endl;
}
int main() {
void (*funcPtr)(int); // Declare function pointer
funcPtr = display; // Assign function
funcPtr(5); // Call function via pointer
return 0;
}
Output:
Number: 5
- Efficient memory access
- Enables dynamic memory
- Used for function callbacks
- Crucial in data structures (linked lists, trees, etc.)
Caution
Misuse can lead to bugs (e.g., memory leaks, dangling pointers), so use wisely.
C++ is a multi-paradigm programming language that supports Object-Oriented Programming (OOP). OOP is based on the concept of objects, which are instances of classes. OOP focuses on the following principles:
- Encapsulation: Grouping related data and functions into a single unit (class).
- Abstraction: Hiding complex details and showing only the necessary parts.
- Inheritance: Deriving new classes from existing ones.
- Polymorphism: The ability of an object to take many forms.
A class is a blueprint or template for creating objects. It defines properties (attributes) and behaviors (methods or functions) that the objects created from the class will have.
Example:
#include <iostream>
using namespace std;
class Car {
public:
// Attributes
string brand;
int year;
// Method (Function)
void startEngine() {
cout << "The " << brand << " engine started.\n";
}
};
int main() {
// Create an object of type Car
Car myCar;
myCar.brand = "Toyota";
myCar.year = 2020;
// Call a method
myCar.startEngine();
return 0;
}
Output:
The Toyota engine started.
Access specifiers define the visibility or accessibility of class members (attributes and methods).
- public: Members are accessible from outside the class.
- private: Members are accessible only within the class.
- protected: Members are accessible within the class and derived classes.
Example:
#include <iostream>
using namespace std;
class Employee {
private:
int salary; // private data member
public:
void setSalary(int s) { // public method
salary = s;
}
int getSalary() { // public method
return salary;
}
};
int main() {
Employee emp;
emp.setSalary(50000); // Accessible because setSalary is public
cout << "Employee salary: " << emp.getSalary() << endl;
return 0;
}
Output:
Employee salary: 50000
- Constructor: Special function that is called when an object is created. It initializes the object.
- Destructor: Special function that is called when an object is destroyed. It is used for cleanup.
Example:
#include <iostream>
using namespace std;
class Student {
public:
string name;
int age;
// Constructor
Student(string n, int a) {
name = n;
age = a;
}
// Destructor
~Student() {
cout << "Object " << name << " is being destroyed.\n";
}
};
int main() {
Student s1("Alice", 20);
cout << s1.name << " is " << s1.age << " years old.\n";
return 0; // Destructor will be called automatically here
}
Output:
Alice is 20 years old.
Object Alice is being destroyed.
The this
pointer is an implicit pointer available to all non-static member functions. It points to the object for which the member function is called.
Example:
#include <iostream>
using namespace std;
class Box {
public:
int length;
Box(int l) {
this->length = l; // Using 'this' pointer to differentiate member and parameter
}
void displayLength() {
cout << "Length of box: " << this->length << endl;
}
};
int main() {
Box box1(10);
box1.displayLength();
return 0;
}
Output:
Length of box: 10
Static members belong to the class itself, rather than to individual objects. They are shared by all instances of the class.
Example:
#include <iostream>
using namespace std;
class Counter {
public:
static int count; // Static member
Counter() {
count++;
}
static void displayCount() { // Static method
cout << "Count: " << count << endl;
}
};
int Counter::count = 0; // Initialize static member outside class
int main() {
Counter c1, c2, c3;
Counter::displayCount(); // Access static method using class name
return 0;
}
Output:
Count: 3
A friend function or friend class can access the private and protected members of another class. Friend functions or classes are declared using the friend
keyword.
Example:
#include <iostream>
using namespace std;
class Box {
private:
int width;
public:
Box() : width(10) {}
// Declaring a friend function
friend void printWidth(Box b);
};
// Friend function definition
void printWidth(Box b) {
cout << "Width of box: " << b.width << endl;
}
int main() {
Box box;
printWidth(box); // Friend function can access private members
return 0;
}
Output:
Width of box: 10
You can create arrays of objects just like any other type.
Example:
#include <iostream>
using namespace std;
class Car {
public:
string brand;
Car(string b) : brand(b) {}
void showBrand() {
cout << "Brand: " << brand << endl;
}
};
int main() {
Car cars[2] = {Car("Toyota"), Car("Honda")};
for (int i = 0; i < 2; i++) {
cars[i].showBrand();
}
return 0;
}
Output:
Brand: Toyota
Brand: Honda
You can also create pointers to objects and use them to access object members.
Example:
#include <iostream>
using namespace std;
class Book {
public:
string title;
Book(string t) : title(t) {}
void showTitle() {
cout << "Book Title: " << title << endl;
}
};
int main() {
Book* bookPtr = new Book("C++ Programming");
bookPtr->showTitle(); // Using pointer to access member function
delete bookPtr; // Free memory
return 0;
}
Output:
Book Title: C++ Programming
Inheritance is one of the core concepts of Object-Oriented Programming (OOP). It allows a class (called the derived class) to inherit properties and methods from another class (called the base class). This helps in code reuse, extension of functionality, and maintaining a hierarchical relationship between classes.
In C++, inheritance is achieved by using the :
symbol. A derived class can inherit members (attributes and methods) from a base class.
Types of Inheritance in C++
- Single Inheritance: A derived class inherits from only one base class.
- Multiple Inheritance: A derived class inherits from more than one base class.
- Multilevel Inheritance: A class inherits from a derived class which, in turn, is derived from another base class.
- Hierarchical Inheritance: Multiple classes inherit from a single base class.
- Hybrid Inheritance: A combination of two or more types of inheritance.
Syntax:
class DerivedClass : accessSpecifier BaseClass {
// Derived class members
};
accessSpecifier
can bepublic
,protected
, orprivate
(more on this below).- The base class is specified after the colon
:
.
- Public Inheritance: Public members of the base class become public members of the derived class.
- Protected Inheritance: Public and protected members of the base class become protected members in the derived class.
- Private Inheritance: Public and protected members of the base class become private members of the derived class.
Example: Single Inheritance
#include <iostream>
using namespace std;
// Base class
class Animal {
public:
void eat() {
cout << "This animal eats food." << endl;
}
};
// Derived class
class Dog : public Animal {
public:
void bark() {
cout << "The dog barks." << endl;
}
};
int main() {
Dog dog;
dog.eat(); // Inherited function from Animal class
dog.bark(); // Function from Dog class
return 0;
}
Output:
This animal eats food.
The dog barks.
Example: Multiple Inheritance
#include <iostream>
using namespace std;
// Base class 1
class Animal {
public:
void eat() {
cout << "This animal eats food." << endl;
}
};
// Base class 2
class Machine {
public:
void start() {
cout << "The machine starts." << endl;
}
};
// Derived class
class Robot : public Animal, public Machine {
public:
void talk() {
cout << "The robot talks." << endl;
}
};
int main() {
Robot robot;
robot.eat(); // Inherited from Animal class
robot.start(); // Inherited from Machine class
robot.talk(); // Defined in Robot class
return 0;
}
Output:
This animal eats food.
The machine starts.
The robot talks.
Example: Multilevel Inheritance
#include <iostream>
using namespace std;
// Base class
class Animal {
public:
void eat() {
cout << "This animal eats food." << endl;
}
};
// Derived class 1
class Mammal : public Animal {
public:
void walk() {
cout << "The mammal walks." << endl;
}
};
// Derived class 2 (from Mammal)
class Dog : public Mammal {
public:
void bark() {
cout << "The dog barks." << endl;
}
};
int main() {
Dog dog;
dog.eat(); // Inherited from Animal
dog.walk(); // Inherited from Mammal
dog.bark(); // Defined in Dog
return 0;
}
Output:
This animal eats food.
The mammal walks.
The dog barks.
Example: Hierarchical Inheritance
#include <iostream>
using namespace std;
// Base class
class Animal {
public:
void eat() {
cout << "This animal eats food." << endl;
}
};
// Derived class 1
class Dog : public Animal {
public:
void bark() {
cout << "The dog barks." << endl;
}
};
// Derived class 2
class Cat : public Animal {
public:
void meow() {
cout << "The cat meows." << endl;
}
};
int main() {
Dog dog;
dog.eat(); // Inherited from Animal
dog.bark(); // Defined in Dog
Cat cat;
cat.eat(); // Inherited from Animal
cat.meow(); // Defined in Cat
return 0;
}
Output:
This animal eats food.
The dog barks.
This animal eats food.
The cat meows.
In C++, constructors are not inherited. However, the constructor of the base class is called before the constructor of the derived class.
Example:
#include <iostream>
using namespace std;
// Base class
class Animal {
public:
Animal() {
cout << "Animal constructor called!" << endl;
}
};
// Derived class
class Dog : public Animal {
public:
Dog() {
cout << "Dog constructor called!" << endl;
}
};
int main() {
Dog dog; // Calls both Animal and Dog constructors
return 0;
}
Output:
Animal constructor called!
Dog constructor called!
In inheritance, the derived class’s destructor is called first, followed by the base class’s destructor. If no destructor is explicitly defined, C++ will automatically call the base class destructor after the derived class destructor.
Example:
#include <iostream>
using namespace std;
// Base class
class Animal {
public:
Animal() {
cout << "Animal constructor called!" << endl;
}
~Animal() {
cout << "Animal destructor called!" << endl;
}
};
// Derived class
class Dog : public Animal {
public:
Dog() {
cout << "Dog constructor called!" << endl;
}
~Dog() {
cout << "Dog destructor called!" << endl;
}
};
int main() {
Dog dog; // Calls constructors and destructors
return 0;
}
Output:
Animal constructor called!
Dog constructor called!
Dog destructor called!
Animal destructor called!
Polymorphism is a key concept in Object-Oriented Programming (OOP) that allows objects of different types to be treated as objects of a common base type. The term polymorphism means "many shapes," and it allows for flexibility in how objects behave based on their specific types.
In C++, polymorphism is achieved through:
- Compile-time Polymorphism (Static Polymorphism)
- Run-time Polymorphism (Dynamic Polymorphism)
Compile-time polymorphism is achieved through function overloading and operator overloading. The decision of which function to call is made at compile time.
Function overloading allows multiple functions with the same name but different parameters (different number or types of parameters).
Example:
#include <iostream>
using namespace std;
class Print {
public:
// Overloaded function for integer type
void display(int i) {
cout << "Integer: " << i << endl;
}
// Overloaded function for float type
void display(float f) {
cout << "Float: " << f << endl;
}
// Overloaded function for string type
void display(string s) {
cout << "String: " << s << endl;
}
};
int main() {
Print obj;
obj.display(5); // Calls the function with int argument
obj.display(3.14f); // Calls the function with float argument
obj.display("Hello"); // Calls the function with string argument
return 0;
}
Output:
Integer: 5
Float: 3.14
String: Hello
Operator overloading allows defining custom behavior for operators when applied to user-defined data types.
Example:
#include <iostream>
using namespace std;
class Complex {
public:
int real, imag;
Complex() : real(0), imag(0) {}
// Operator overloading for adding two complex numbers
Complex operator + (const Complex &c) {
Complex temp;
temp.real = real + c.real;
temp.imag = imag + c.imag;
return temp;
}
void display() {
cout << real << " + " << imag << "i" << endl;
}
};
int main() {
Complex c1, c2, c3;
c1.real = 5; c1.imag = 3;
c2.real = 2; c2.imag = 7;
c3 = c1 + c2; // Using overloaded operator +
c3.display(); // Output: 7 + 10i
return 0;
}
Output:
7 + 10i
Run-time polymorphism is achieved using function overriding in the context of inheritance. The decision of which function to call is made at runtime based on the type of object pointed to by the base class pointer.
A virtual function is a function defined in the base class that can be overridden in the derived class. The function call is resolved at runtime based on the object type that the base class pointer is pointing to.
To enable run-time polymorphism, you need to declare a function in the base class as virtual
.
Example:
#include <iostream>
using namespace std;
// Base class
class Animal {
public:
virtual void sound() { // Virtual function
cout << "Animal makes a sound" << endl;
}
};
// Derived class
class Dog : public Animal {
public:
void sound() override { // Overridden function
cout << "Dog barks" << endl;
}
};
// Derived class
class Cat : public Animal {
public:
void sound() override { // Overridden function
cout << "Cat meows" << endl;
}
};
int main() {
Animal *animal;
Dog dog;
Cat cat;
// Using base class pointer to call derived class functions
animal = &dog;
animal->sound(); // Calls Dog's sound() method
animal = &cat;
animal->sound(); // Calls Cat's sound() method
return 0;
}
Output:
Dog barks
Cat meows
- The
sound()
function in theAnimal
class is a virtual function, which allows the derived classes (Dog
,Cat
) to override it. - When the base class pointer (
animal
) points to aDog
object, it calls theDog
'ssound()
method. - Similarly, when the base class pointer points to a
Cat
object, it calls theCat
'ssound()
method.
A pure virtual function is a virtual function that has no implementation in the base class, making the class abstract. It is declared using = 0
in the declaration.
#include <iostream>
using namespace std;
class Shape {
public:
virtual void draw() = 0; // Pure virtual function, making Shape an abstract class
};
class Circle : public Shape {
public:
void draw() override {
cout << "Drawing Circle" << endl;
}
};
class Rectangle : public Shape {
public:
void draw() override {
cout << "Drawing Rectangle" << endl;
}
};
int main() {
Shape* shape;
Circle circle;
Rectangle rectangle;
shape = &circle;
shape->draw(); // Output: Drawing Circle
shape = &rectangle;
shape->draw(); // Output: Drawing Rectangle
return 0;
}
Output:
Drawing Circle
Drawing Rectangle
In this example:
Shape
is an abstract class because it has a pure virtual function (draw
).- The
Circle
andRectangle
classes provide implementations for the pure virtual function. - You cannot create an object of the
Shape
class directly.
- Code Reusability: With polymorphism, one function can work with objects of different types, leading to less code duplication.
- Maintainability: Polymorphism makes the system easier to extend and maintain, as you can add new derived classes without modifying existing code.
- Flexibility: Polymorphism allows you to write more general code that can handle new types of objects, making the program flexible.
Encapsulation is one of the fundamental concepts of Object-Oriented Programming (OOP) in C++. It refers to the bundling of data and the functions that operate on that data into a single unit (class), while also restricting direct access to some of the object's components. This is achieved using access specifiers (private
, protected
, public
).
Encapsulation promotes data hiding, security, and modular code structure.
Key Concepts of Encapsulation:
Feature | Description |
---|---|
Class | Combines data (variables) and methods (functions) in one unit |
Access Specifiers | Control access to class members (private , protected , public ) |
Private Members | Cannot be accessed directly from outside the class |
Public Methods | Used to access and modify private data safely (getters/setters) |
Example: Simple Encapsulation
#include <iostream>
using namespace std;
class Account {
private:
// Private data member
double balance;
public:
// Constructor to initialize balance
Account(double b) {
if (b >= 0)
balance = b;
else
balance = 0;
}
// Getter function to access balance
double getBalance() {
return balance;
}
// Setter function to update balance
void deposit(double amount) {
if (amount > 0)
balance += amount;
}
void withdraw(double amount) {
if (amount > 0 && amount <= balance)
balance -= amount;
else
cout << "Invalid withdrawal amount." << endl;
}
};
int main() {
Account myAccount(1000); // Create object with initial balance
cout << "Initial Balance: $" << myAccount.getBalance() << endl;
myAccount.deposit(500);
cout << "After Deposit: $" << myAccount.getBalance() << endl;
myAccount.withdraw(300);
cout << "After Withdrawal: $" << myAccount.getBalance() << endl;
// myAccount.balance = 10000; // ❌ Not allowed (private access)
return 0;
}
Output:
Initial Balance: $1000
After Deposit: $1500
After Withdrawal: $1200
- Data Hiding: Internal state is hidden from outside access.
- Improved Security: Only validated changes are allowed through public methods.
- Modularity: Each object manages its own state and behavior.
- Easy Maintenance: Implementation changes inside the class don’t affect external code.
- Better Control: You can control how data is accessed or modified via setters/getters.
Abstraction in C++ is an OOP principle that allows you to hide complex implementation details and show only the essential features of an object. It simplifies programming by separating what an object does from how it does it.
In C++, abstraction is mainly achieved through:
- Abstract Classes (with at least one pure virtual function)
- Interfaces (fully abstract classes)
- Access Specifiers (
private
,protected
,public
) to hide implementation details
Key Concepts:
Concept | Description |
---|---|
Abstraction | Hides internal implementation, shows only necessary features |
Abstract Class | A class with at least one pure virtual function (= 0 ) |
Pure Virtual Function | A function declared in a base class to be overridden in derived class |
Interface | A class with only pure virtual functions, used as a contract |
Example: Using Abstract Class
#include <iostream>
using namespace std;
// Abstract class
class Shape {
public:
// Pure virtual function
virtual void draw() = 0;
void commonMethod() {
cout << "This is a shared method in abstract class.\n";
}
};
// Derived class: Circle
class Circle : public Shape {
public:
void draw() override {
cout << "Drawing a Circle.\n";
}
};
// Derived class: Rectangle
class Rectangle : public Shape {
public:
void draw() override {
cout << "Drawing a Rectangle.\n";
}
};
int main() {
Shape* s1 = new Circle();
Shape* s2 = new Rectangle();
s1->draw(); // Output: Drawing a Circle.
s2->draw(); // Output: Drawing a Rectangle.
s1->commonMethod(); // Output: This is a shared method in abstract class.
delete s1;
delete s2;
return 0;
}
Output:
Drawing a Circle.
Drawing a Rectangle.
This is a shared method in abstract class.
- Hide Complexity: Keep implementation details hidden from the user.
- Improve Maintainability: Changing internal logic doesn’t affect users.
- Enhance Modularity: Work with interfaces and abstract classes.
- Encourage Polymorphism: Let derived classes provide specific behaviors.
- Code Reusability: Share base behaviors and override specifics.
Operator Overloading in C++ allows you to redefine the meaning of operators (+
, -
, ==
, <<
, etc.) for user-defined types (like classes and structs). This improves code readability, flexibility, and enables intuitive syntax when working with objects.
- Makes custom objects behave like built-in types.
- Enhances code clarity and usability.
- Enables operations like addition, comparison, assignment, etc., on class objects.
Syntax:
return_type operator symbol (parameters) {
// implementation
}
Example: Overload +
for a Point
Class
#include <iostream>
using namespace std;
class Point {
int x, y;
public:
Point(int x = 0, int y = 0) : x(x), y(y) {}
// Overload + operator
Point operator+(const Point& p) {
return Point(x + p.x, y + p.y);
}
void display() {
cout << "(" << x << ", " << y << ")" << endl;
}
};
int main() {
Point p1(2, 3), p2(4, 5), result;
result = p1 + p2; // using overloaded + operator
result.display(); // Output: (6, 8)
return 0;
}
Output:
(6, 8)
Operator | Meaning |
---|---|
+ |
Addition |
- |
Subtraction |
* |
Multiplication |
/ |
Division |
== , != |
Comparison |
<< , >> |
Stream insertion/extraction |
= |
Assignment |
[] |
Subscript (array indexing) |
() |
Function call |
-> |
Member access via pointer |
-
At least one operand must be a user-defined type.
-
You cannot overload:
::
(scope resolution).
(member access).*
(member pointer access)sizeof
,typeid
,alignof
, etc.
-
Overloaded operators don’t change precedence or associativity.
Example: Overload ==
and <<
#include <iostream>
using namespace std;
class Book {
string title;
int pages;
public:
Book(string t, int p) : title(t), pages(p) {}
// Overload ==
bool operator==(const Book& b) {
return (title == b.title && pages == b.pages);
}
// Overload <<
friend ostream& operator<<(ostream& out, const Book& b) {
out << "Book: " << b.title << ", Pages: " << b.pages;
return out;
}
};
int main() {
Book b1("C++ Basics", 300), b2("C++ Basics", 300);
if (b1 == b2)
cout << "Books are equal" << endl;
cout << b1 << endl;
return 0;
}
Output:
Books are equal
Book: C++ Basics, Pages: 300
Templates in C++ allow you to write generic and reusable code. They enable functions and classes to operate with generic types, so you can write a single codebase to work with different data types.
Types of Templates in C++
- Function Templates
- Class Templates
These allow the creation of a single function that can work with any data type.
Syntax:
template <typename T>
T functionName(T arg) {
// function body
}
You can also use class
instead of typename
— both work the same.
Example:
#include <iostream>
using namespace std;
template <typename T>
T add(T a, T b) {
return a + b;
}
int main() {
cout << add<int>(3, 4) << endl; // 7
cout << add<double>(2.5, 4.3) << endl; // 6.8
cout << add<string>("Hi ", "there!") << endl; // Hi there!
return 0;
}
Output:
7
6.8
Hi there!
Class templates allow the definition of generic classes to handle data of any type.
Syntax:
template <class T>
class ClassName {
T data;
public:
ClassName(T val) : data(val) {}
void show() { cout << data << endl; }
};
Example:
#include <iostream>
using namespace std;
template <class T>
class Box {
T value;
public:
Box(T val) : value(val) {}
void display() { cout << "Value: " << value << endl; }
};
int main() {
Box<int> intBox(10);
Box<string> strBox("Hello");
intBox.display(); // Value: 10
strBox.display(); // Value: Hello
return 0;
}
Output:
Value: 10
Value: Hello
Example:
#include <iostream>
#include <string>
using namespace std;
template <class T1, class T2>
class Pair {
T1 first;
T2 second;
public:
Pair(T1 a, T2 b) : first(a), second(b) {}
void show() {
cout << "First: " << first << ", Second: " << second << endl;
}
};
int main() {
Pair<int, string> p(101, "Alice");
p.show(); // First: 101, Second: Alice
return 0;
}
Output:
First: 101, Second: Alice
Important
- Templates are compiled when used, not when defined.
- You can provide default types to templates.
- Templates support specialization (custom behavior for specific types).
Templates can coexist with regular functions. The compiler chooses the best match.
Example:
#include <iostream>
using namespace std;
void show(int x) {
cout << "Regular function: " << x << endl;
}
template <typename T>
void show(T x) {
cout << "Template function: " << x << endl;
}
int main() {
show(100); // Calls regular function
show(3.14); // Calls template function
return 0;
}
Output:
Regular function: 100
Template function: 3.14
C++ supports powerful user-defined data types that help group different kinds of data under a single name:
struct
→ Structureunion
→ Unionenum
→ Enumeration
A structure in C++ allows grouping variables of different types under one user-defined name.
Syntax:
struct StructName {
datatype member1;
datatype member2;
...
};
Example:
#include <iostream>
#include <string>
using namespace std;
struct Person {
string name;
int age;
};
int main() {
Person p1 = {"Alice", 25};
cout << "Name: " << p1.name << endl;
cout << "Age: " << p1.age << endl;
return 0;
}
Output:
Name: Alice
Age: 25
A union is like a structure but all members share the same memory location. Only one member can hold a value at any one time.
Syntax:
union UnionName {
datatype member1;
datatype member2;
...
};
Example:
#include <iostream>
using namespace std;
union Data {
int i;
float f;
};
int main() {
Data d;
d.i = 10;
cout << "d.i = " << d.i << endl;
d.f = 3.14f;
cout << "d.f = " << d.f << endl;
// d.i is now overwritten
cout << "d.i after setting d.f = " << d.i << endl;
return 0;
}
Output: (Memory Overlap)
d.i = 10
d.f = 3.14
d.i after setting d.f = 1078523331
Caution
Memory sharing causes unexpected value in d.i
after assigning to d.f
.
An enum assigns names to a set of integer constants to improve code readability.
Syntax:
enum EnumName { CONST1, CONST2, CONST3, ... };
- Default:
CONST1 = 0
,CONST2 = 1
, and so on.
Example:
#include <iostream>
using namespace std;
enum Weekday { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday };
int main() {
Weekday today = Friday;
cout << "Numeric value of Friday: " << today << endl;
return 0;
}
Output:
Numeric value of Friday: 5
Custom Enum Values
You can assign custom values to enum constants:
enum Color { Red = 1, Green = 3, Blue = 5 };
This lets you represent specific values explicitly.
Dynamic memory allocation in C++ lets you allocate memory at runtime using pointers and the new
and delete
operators (instead of malloc
, calloc
, realloc
, and free
in C).
It provides flexibility to create memory that can grow or shrink during execution.
Memory Functions in C++
C Function | C++ Equivalent | Description |
---|---|---|
malloc() |
new |
Allocates memory |
calloc() |
new (initialized manually) |
Allocates & initializes memory |
realloc() |
Manually recreate + copy | Resize allocated memory block |
free() |
delete / delete[] |
Frees allocated memory |
The new
operator dynamically allocates memory and returns a pointer to it. Unlike malloc()
, it does not require casting and constructs objects if needed.
Example:
#include <iostream>
using namespace std;
int main() {
int* arr = new int[3]; // allocate memory for 3 integers
arr[0] = 10;
arr[1] = 20;
arr[2] = 30;
for (int i = 0; i < 3; i++) {
cout << arr[i] << " ";
}
delete[] arr; // free memory
return 0;
}
Output:
10 20 30
C++ doesn't have a calloc
equivalent, but you can manually initialize after allocation or use modern containers (e.g. vector
). Here's how to emulate calloc
:
Example:
#include <iostream>
using namespace std;
int main() {
int* arr = new int[3](); // () initializes all to zero
for (int i = 0; i < 3; i++) {
cout << arr[i] << " ";
}
delete[] arr;
return 0;
}
Output:
0 0 0
C++ has no direct realloc()
equivalent. To resize:
- Allocate new memory
- Copy old values
- Delete old memory
Example:
#include <iostream>
using namespace std;
int main() {
int* arr = new int[2];
arr[0] = 5;
arr[1] = 10;
// Create a new array with larger size
int* newArr = new int[4];
// Copy existing data
for (int i = 0; i < 2; i++) {
newArr[i] = arr[i];
}
// Add new data
newArr[2] = 15;
newArr[3] = 20;
// Delete old array
delete[] arr;
// Print new array
for (int i = 0; i < 4; i++) {
cout << newArr[i] << " ";
}
delete[] newArr;
return 0;
}
Output:
5 10 15 20
delete
and delete[]
are used to free dynamically allocated memory in C++.
Example:
#include <iostream>
using namespace std;
int main() {
int n = 5;
int* arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = (i + 1) * 10;
}
cout << "Values in the array: ";
for (int i = 0; i < n; i++) {
cout << arr[i] << " ";
}
cout << endl;
delete[] arr;
cout << "Memory successfully freed." << endl;
return 0;
}
Output:
Values in the array: 10 20 30 40 50
Memory successfully freed.
In C++, Type Conversion and Typecasting refer to changing a variable from one data type to another. This is essential in many operations, especially when dealing with arithmetic between different types or converting user input/output types.
There are two main types of conversions:
- Implicit Conversion: Done automatically by the compiler
- Explicit Conversion: Done manually by the programmer (called typecasting)
The compiler automatically converts one data type to another (usually a higher type to avoid data loss).
Rule:
Lower → Higher rank:
bool → char → int → float → double
Example:
#include <iostream>
using namespace std;
int main() {
int i = 42;
double d = i; // int implicitly converted to double
cout << "i = " << i << endl;
cout << "d = " << d << endl;
return 0;
}
Output:
i = 42
d = 42
You manually cast a value from one type to another.
Syntax: (3 ways)
-
C-style cast:
(type)expression
-
Function-style cast:
type(expression)
-
C++ cast operators:
static_cast<type>(expression)
dynamic_cast<type>(expression)
(for polymorphic classes)const_cast<type>(expression)
(removeconst
)reinterpret_cast<type>(expression)
(bitwise conversion)
Example: C-style & Function-style Cast
#include <iostream>
using namespace std;
int main() {
double pi = 3.14159;
int intPi1 = (int)pi; // C-style
int intPi2 = int(pi); // Function-style
cout << "Original: " << pi << endl;
cout << "C-style cast: " << intPi1 << endl;
cout << "Function-style cast: " << intPi2 << endl;
return 0;
}
Output:
Original: 3.14159
C-style cast: 3
Function-style cast: 3
Example: static_cast
#include <iostream>
using namespace std;
int main() {
float f = 9.81;
int i = static_cast<int>(f); // Converts float to int
cout << "Original float: " << f << endl;
cout << "After static_cast: " << i << endl;
return 0;
}
Output:
Original float: 9.81
After static_cast: 9
Example: reinterpret_cast
#include <iostream>
using namespace std;
int main() {
int x = 65;
char* ch = reinterpret_cast<char*>(&x);
cout << "First byte of x as char: " << *ch << endl;
return 0;
}
Output: (on little-endian systems)
First byte of x as char: A
static_cast
- Safe, standard conversion between types (int ↔ float, base ↔ derived)dynamic_cast
- Used for safe downcasting in polymorphic class hierarchies.const_cast
- Add/removeconst
orvolatile
qualifierreinterpret_cast
- Low-level reinterpretation (dangerous, for bit-level tricks)
Tip
- Use
static_cast
over C-style for clarity and type safety. - Avoid
reinterpret_cast
unless absolutely necessary. - Avoid implicit conversions when there's risk of precision loss or truncation.
File handling in C++ allows you to create, write, read, and manipulate files (text or binary) using file streams provided by the <fstream>
library.
C++ provides three main file stream classes in the <fstream>
header:
Class | Description |
---|---|
ifstream |
Input stream – for reading files (in ) |
ofstream |
Output: stream – for writing files (out ) |
fstream |
Input/output stream – for both reading and writing (in/out ) |
Include the necessary header:
#include <fstream>
Syntax to open a file:
ifstream fin("file.txt"); // for reading
ofstream fout("file.txt"); // for writing
fstream fio("file.txt"); // for both
Alternative using .open()
method:
fin.open("file.txt");
Closing the file:
fin.close();
Example: Writing to a File
#include <iostream>
#include <fstream>
using namespace std;
int main() {
ofstream fout("example.txt"); // creates and opens the file
if (!fout) {
cout << "File couldn't be opened!" << endl;
return 1;
}
fout << "Hello, C++ File Handling!" << endl;
fout << "This is a sample file." << endl;
fout.close(); // don't forget to close the file
return 0;
}
Output: (in example.txt
)
Hello, C++ File Handling!
This is a sample file.
Example: Reading from a File
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main() {
ifstream fin("example.txt"); // open file for reading
string line;
if (!fin) {
cout << "File couldn't be opened!" << endl;
return 1;
}
while (getline(fin, line)) {
cout << line << endl;
}
fin.close();
return 0;
}
Output:
Hello, C++ File Handling!
This is a sample file.
Example: Reading and Writing (Using fstream
)
#include <iostream>
#include <fstream>
using namespace std;
int main() {
fstream file;
// open file for both reading and writing
file.open("data.txt", ios::out | ios::in | ios::trunc);
if (!file) {
cout << "File couldn't be opened!" << endl;
return 1;
}
file << "Welcome to C++ fstream!" << endl;
// Go back to the beginning of file to read
file.seekg(0);
string line;
while (getline(file, line)) {
cout << line << endl;
}
file.close();
return 0;
}
Mode | Description |
---|---|
ios::in |
Open for reading |
ios::out |
Open for writing |
ios::app |
Append to end of file |
ios::trunc |
Delete content if file exists |
ios::binary |
Open in binary mode |
You can combine them using |
(bitwise OR):
fstream file("data.txt", ios::in | ios::out);
Example: Appending to a File
#include <iostream>
#include <fstream>
using namespace std;
int main() {
ofstream fout("example.txt", ios::app); // append mode
fout << "New line added using append mode.\n";
fout.close();
return 0;
}
Function | Description |
---|---|
file.is_open() |
Returns true if file opened successfully |
file.eof() |
Returns true if end-of-file reached |
file.fail() |
Returns true if operation failed |
file.good() |
Returns true if no error |
Preprocessor directives in C++ are commands for the preprocessor that execute before the compilation phase. They are used to:
- Include files
- Define constants/macros
- Enable conditional compilation
- Give special instructions to the compiler
All preprocessor directives begin with #
and do not end with a semicolon.
Common Preprocessor Directives in C++
Directive | Description |
---|---|
#include |
Includes standard or user-defined header files |
#define |
Defines macros/constants |
#undef |
Undefines (removes) a previously defined macro |
#ifdef , #ifndef |
Conditional compilation based on whether macros are defined |
#else , #elif |
Alternative blocks for conditional compilation |
#endif |
Ends a conditional block |
#if |
Compiles code if a condition is true |
#pragma |
Provides compiler-specific instructions |
Used to include header files (standard or user-defined).
Example:
#include <iostream> // Standard header
int main() {
std::cout << "Hello, World!" << std::endl;
return 0;
}
Output:
Hello, World!
Defines a symbolic constant or macro to be replaced before compilation.
Example:
#include <iostream>
#define PI 3.14
int main() {
float area = PI * 5 * 5;
std::cout << "Area of circle: " << area << std::endl;
return 0;
}
Output:
Area of circle: 78.5
Removes a previously defined macro.
Example:
#include <iostream>
#define MAX 100
int main() {
std::cout << "Max value: " << MAX << std::endl;
#undef MAX
// std::cout << MAX << std::endl; // Error: MAX is undefined
return 0;
}
Output:
Max value: 100
Includes code if a macro is defined or not defined.
Example:
#include <iostream>
#define DEBUG
int main() {
#ifdef DEBUG
std::cout << "Debugging is enabled." << std::endl;
#else
std::cout << "Debugging is not enabled." << std::endl;
#endif
return 0;
}
Output:
Debugging is enabled.
Selects among different blocks during compilation.
Example:
#include <iostream>
#define VERBOSE 0
int main() {
#if VERBOSE
std::cout << "Verbose mode is enabled." << std::endl;
#else
std::cout << "Verbose mode is disabled." << std::endl;
#endif
return 0;
}
Output:
Verbose mode is disabled.
Provides additional information to the compiler, such as optimizations or warnings.
Example (GCC specific):
#include <iostream>
#pragma GCC optimize("O3") // Compiler optimization
int main() {
for (int i = 0; i < 1000000; ++i); // Dummy loop
std::cout << "Loop completed with optimization." << std::endl;
return 0;
}
Output:
Loop completed with optimization.
Warning
The actual performance gain won't be visible for such a small loop.
In C++, error handling is done using exceptions, which provide a way to detect and manage runtime errors without crashing the program.
Key Concepts:
Term | Description |
---|---|
try |
Block of code that might throw an exception |
throw |
Used to raise an exception |
catch |
Block of code that handles the exception |
exception |
An object or value representing the error |
std::exception |
Base class for standard exceptions in <exception> header |
Syntax:
try {
// Code that may throw an exception
throw exception_value;
}
catch (exception_type variable) {
// Handle the exception
}
Example: Division by Zero
#include <iostream>
using namespace std;
int main() {
int a = 10, b = 0;
try {
if (b == 0)
throw "Division by zero not allowed!";
cout << "Result: " << a / b << endl;
}
catch (const char* msg) {
cout << "Error: " << msg << endl;
}
return 0;
}
Output:
Error: Division by zero not allowed!
Example: Using Standard Exception
#include <iostream>
#include <stdexcept>
using namespace std;
int main() {
try {
throw runtime_error("Something went wrong!");
}
catch (const runtime_error& e) {
cout << "Caught runtime_error: " << e.what() << endl;
}
return 0;
}
Output:
Caught runtime_error: Something went wrong!
Example: Multiple Catch Blocks
#include <iostream>
using namespace std;
int main() {
try {
int choice = 2;
if (choice == 1)
throw 100;
else if (choice == 2)
throw 3.14;
else
throw "Unknown error!";
}
catch (int x) {
cout << "Caught integer exception: " << x << endl;
}
catch (double d) {
cout << "Caught double exception: " << d << endl;
}
catch (const char* msg) {
cout << "Caught string exception: " << msg << endl;
}
return 0;
}
Output:
Caught double exception: 3.14
Example: Catch-All Handler
#include <iostream>
using namespace std;
int main() {
try {
throw 'X';
}
catch (...) {
cout << "Caught an unknown exception!" << endl;
}
return 0;
}
Output:
Caught an unknown exception!
Exception Class | Header | Description |
---|---|---|
std::exception |
<exception> |
Base class for all standard exceptions |
std::runtime_error |
<stdexcept> |
Errors detected at runtime |
std::logic_error |
<stdexcept> |
Logic errors in program (e.g., invalid_argument) |
std::out_of_range |
<stdexcept> |
Index out of range |
std::bad_alloc |
<new> |
Memory allocation failure |
Tip
- Use exceptions for exceptional situations — not for regular control flow.
- Always catch by reference when using classes like
std::exception
. - Prefer using standard exceptions (
std::runtime_error
,std::out_of_range
, etc.). - Use
noexcept
keyword to specify functions that don't throw exceptions. - Clean up dynamically allocated resources using RAII or smart pointers.
This section offers a curated collection of frequently encountered C++ programming problems, complete with detailed solutions and sample outputs. It's tailored to strengthen your understanding of core concepts such as conditionals, loops, functions, arrays, pointers, and dynamic memory—through active, hands-on practice.
Explore problem-solving in action:
C++ Code Solutions Repository
Build real-world skills:
Check out beginner-friendly to intermediate-level projects here:
C++ Mini Projects Repository