C++

# Program Structure

#include<iostream>
using namespace std;

int main(){
    cout << "Hello World" << endl;

    return 0;
}

# Compile & Execute

The g++ is a compiler that is used to compile programs written in the C++ programming language. It is part of the GNU Compiler Collection (GCC).

• Compiling Program :
g++ file.cpp
g++ file.cpp -o exe_name
• Executing Program :
./a.out
./exe_name

# Input & Output

The iostream (or input-output stream) is a C++ Standard Library (or header file) that provides definitions for the istream and ostream classes. It is used to read input from a stream of characters, such as a console or file, and write output data to the console or file.

• Ostream Class :

The ostream (or output stream) is used to write a stream of characters as output to the console or a file.

  • Console Output : The cout (or console-output) is a predefined object of the ostream class. It is used with a stream insertion operator (<<) to display output.

    cout << "Hello World";
    cout << "\nValue of X is " << x;
  • End Line : The endl (or end-line) is a predefined object of the ostream class. It is used to insert new line characters and flush the stream.

    cout << "Hello World" << endl;
• Istream Class :

The istream (or input stream) is used to handle input operations from a stream of characters (such as the console or a file).

  • Console Input : The cin (or console input) is a predefined object of the istream class. It is used with the stream extraction operator (>>) to read input from the console.

    cin >> n;
    cin >> a >> b >> c;
• Escape Sequences :

The escape sequences are special non-printing characters that are used to control the printing behavior of the output stream objects.

Escape Char Description
\a Alarm or beep sound
\b Backspace
\f Form feed
\n New line
\r Return
\t Tab space
\\ Backslash
\' Single quote
\? Question mark
\nnn Octal number
\xhh Hexadecimal number
\0 Null

# Comments

• Single-Line Comment :

// is used for single-line comment.

// This is single-line comment.

cout << "Hello World"; // This is comment
• Multi-Line Comment :

/* */ is used for multi-line comment.

/* This is
multi-line comment. */

int x = 22; /* This is multi-line
comment. */

# Variables

Syntax :
data_type variable_name;
int a;
int x, y, z = 17;
int n = 22;
string name = "Mandar";
• Local & Global Variables :

The Local variables are declared inside a function or block and can be used only by statements that are inside that function or block. The Global variables are defined outside of all the functions, can be accessed by any function, and hold their value throughout the life of program.

Ex :
#include<iostream>
using namespace std;

// Global Variables :
float f = 17.22;
int n = 0;

int main(){
    // Local Variables :
    int x, y = 22;
    float a, b;
    a = b = 22.17;

    return 0;
}

# Data Types

A data type specifies the type of data that a variable can store such as integer, floating, character, etc.

• Primitive Data Types :

A primitive type is predefined and built into a programming language. It is named with a reserved keyword.

Date Type Size Description
bool 1 byte boolean values (true or false)
char 1 byte single character, letter, number or ASCII values
int 4 byte integers (non-decimals)
float 4 byte fractional numbers (upto 7 decimal digits)
double 8 byte fractional numbers (upto 15 decimal digits)
void - represents no type or absence of type
• Data Type Modifier :

Modifiers are prefix keywords that change the properties of the basic primitive data type.

Date Type Size Description
signed 4 byte only negative numbers
unsigned 4 byte only positive numbers
short 2-4 byte small numbers (machine dependent)
long 4-8 byte large numbers (machine dependent)
• Date Type Qualifiers :

A type qualifier is used to refine the declaration of a variable, a function, and parameters.

Keyword Description
const constant (read-only variables that can't be reassigned)
volatile volatile variables' value could change unexpectedly, and no optimization is done on them.
restrict restrict is used for pointers, which tells the compiler that a restricted pointer is the only way to access the object pointed at it (no other pointer can point to the same object).
const int COUNT = 1;
• Typedef Keyword :

The typedef keyword assigns a new name or alias to an existing data type.

Syntax :
typedef type newname;
typedef int feet;
feet distance;
distance = 2002;

cout << "Distance = " << distance << endl;

# Storage Classes

The Storage class defines the scope (visibility) and life-time of variables and/or functions within a C++ program.

Syntax :
class type name
C++ uses 5 storage classes, namely -
Class Lifetime Visibility Default Value
auto function/block local garbage
extern throughout program global zero
static throughout program local zero
register function/block local garbage
mutable class local garbage
Ex :
auto int x;
register int amount = 0;
static int count = 1;

# Operators

• Arithmetic Operators :
Operator Description
+ Addition
- Substraction
* Multiplication
/ Division
% Modulus
++ Increment
-- Decrement
• Relational Operators :
Operator Description
== Equal to
!= Not equal to
> Greater than
< Less than
>= Greater than or equal to
<= Less than or equal to
• Logical Operators :
Operator Description
&& Logical and
|| Logical or
! Logical not
• Bitwise Operators :
Operator Description
& Bitwise AND
| Bitwise OR
^ Bitwise XOR
~ One's Complement (unary)
<< Left Shift Operator
>> Right Shift Operator
• Sizeof Operator :

The sizeof() operator or function returns the amount of memory that is allocated to data types in bytes.

int x = 22;
cout << sizeof(x);
• Ternary Operator :
[condition] ? [expr_1] : [expr_2]

If the condition is true, then expression 1 is evaluated; otherwise, expression 2 is evaluated.

int a=5, b=10, large;
large = a > b ? a : b;

cout << "Largest number is " << large << endl;
• Type Casting Operator :

Typecasting is the conversion of one data type into another by using a casting operator.

Syntax :
type(expression)
(type)expression
Ex :
// Casting float into int:
cout << int(22.17);
cout << (int)17.22;
• Membership Operator :

The dot operator (.) and the arrow operator (->) are used to reference individual members of classes, structures, and unions. To access members through a pointer, the arrow operator is used.

struct Classroom {
   int roll;
   char name[20];
};

int main(){
    // Using dot operator :
    struct Classroom s = { 17, "Mandar" };
    cout << "Roll: " << s.roll << "\nName: "<< s.name << endl;

    // Using arrow operator (pointer) :
    struct Classroom *sp = &s;
    cout << "Roll: " << sp->roll << "\nName: "<< sp->name;

    return 0;
}
• Referencing & Dereferencing Operator :

The referencing operator (&) is used for accessing the memory location of a variable, and the dereferncing operator (*) is used for accessing the value stored at the memory location.

// Referencing:
int v = 22;
cout << "Address of v is " << &v;

// Dereferencing:
cout << "\nValue of v is " << *(&v);
• Scope Resolution Operator :

The scope resolution operator (::) is used to access variables, functions, or classes defined in a specific scope or namespace. It can be used to define the member function outside of the class and to access the static members of a class.

int x = 100;

int main(){
    int x = 50;
    cout << "Local X is " << x << endl;
    cout << "Global X is " << ::x << endl;

    return 0;
}

# Decision Making

• If Statement :
Syntax :
if(condition){
    // statements_if_true
}
Ex :
int a=10, b=20;

if(a > b){
    cout << "A is larger than B";
}
• If-Else Statement :
Syntax :
if(condition){
    // statements_if_true
} else {
    // statements_if_false
}
Ex :
int a=10, b=20;

if(a > b){
    cout << "A is greater than B";
} else {
    cout << "A is smaller than B";
}
• Else-If Statement :
Syntax :
if(condition){
    // statements_if_true
} else if (condition) {
    // statements_if_true
} else {
    // statements_if_false
}
Ex :
int a=10, b=20;

if(a > b){
    cout << "A is greater than B";
} else if (a < b) {
    cout << "A is smaller than B";
} else {
    cout << "A is equal to B";
}
• Nested If-Else :
Ex :
int age = 22;

if(age > 0){
    if(age < 18)
        cout << "You are young";
    else if ( age >= 18)
        cout << "You are adult";
} else {
    if(age < 0)
        cout << "Age cannot be negative";
    else
        cout << "Age cannot be zero";
}
• Switch Case :

A switch statement allows a variable to be tested for equality against a list of values.

Syntax :
switch(expression){
    case constant-expression-1 :
        statement(s);
        break;
    case constant-expression-2 :
        statement(s);
        break;
    case constant-expression-N :
        statement(s);
        break;

    default :
        statement(s);
}
Ex :
int day = 3;

switch(day){
    case 1 :
        cout << "Mon";
        break;
    case 2 :
        cout << "Tue";
        break;
    case 3 :
        cout << "Wed";
        break;
    case 4 :
        cout << "Thu";
        break;
    case 5 :
        cout << "Fri";
        break;
    case 6 :
        cout << "Sat";
        break;
    case 7 :
        cout << "Sun";
        break;

    default :
        cout << "Incorrect Day!";
}

# Loops

• While Loop :

Generally, when the number of iterations is unknown, the while loop is used.

Syntax :
while(condition) {
    statement(s);
}
Ex :
int n = 1;
while(n <= 5){
    cout << "Hello World";
    n++;
}
• Do-While Loop :
Syntax :
do {
    statement(s);
} while(condition);
Ex :
int n = 1;
do {
    cout << "Hello World";
    n++;
} while(n <= 5)
• For Loop :

Generally, when the number of iterations is known, the for loop is used.

Syntax :
for ( init; condition; increment ){
    statement(s);
}
Ex :
for(int i=1; i<=5; i++){
    cout << "Hello World";
}
• Nested Loops :
Ex :
for(int i=1; i<=5; i++)
    for(int j=1; j<=i; j++)
        cout << "Hello World";

# Loop Control Statements

• Break Statement :

Terminates the loop or switch statement and transfers execution to the statement immediately following the loop or switch.

Syntax :
break;
Ex :
int n = 1;
while(n <= 100){
    if (n == 22) break;
    cout << "Hello World";
    n++;
}
• Continue Statement :

This causes the loop to skip the remainder of its body and immediately retest its condition prior to reiterating.

Syntax :
continue;
Ex :
int n = 1;
while(n <= 100){
    if (n%2 == 0) continue;
    cout << "Hello World";
    n++;
}
• Goto Statement :

Transfers control to the labelled statement.

Syntax :
goto label;
labal:
    statement(s);
Ex :
int n;
INPUT:
cout << "Enter Odd Number :";
cin >> n;
if (n%2 == 0) goto INPUT;

# Strings

Strings are one-dimensional arrays of characters terminated by the null character '\0'. There are two ways of using strings in C++ :

  1. String as Char Array (C-style)
  2. String Class (recommended)
• String as Char Array :

Declaring a string as a character array as in the C language

Syntax :
char name[];
Ex :
char greet[] = "Hello World";
char name[10];
name = "Mandar";
• String Class :

The standard C++ library provides a string class. For this, we must include the library/header file <string>.

Syntax :
string name;
Ex :
#include<iostream>
#include<string>
using namespace std;

int main(){
    string greet = "Hello World";
    
    cout << greet << endl;
    cout << "String Length is " << greet.length() << endl;

    return 0;
}
• String Functions :
Function Description
str.length() Returns the length of string
str.append(string) Appends the string at the end of str.
str.copy(string,len,pos) Copies c-style string of size (len) from position (pos) to str
str.replace(pos,len,string) Replace string of size (len) from position (pos) in str
str.compare(str2) Returns 0 if both are the same; less than 0 if str<str2; greater than 0 if str>str2.
str.find(string) Find first occurance of string in str and returns the position
str.substr(pos,len) Returns sub-string of length (len) from the string from position (pos)
str.c_str() Returns C string equivalent (null-terminated sequence of characters)

# Arrays

An array is a fixed-size sequential collection of elements of the same type. All arrays consist of contiguous memory locations. Array indexes start with 0: [0] is the first element. Arrays cannot be reinitialized.

Declaring array :
type name[size];
Initializing array :
type name[N] = { element1, element2, ..., elementN };
type name[] = { element1, element2, ..., elementN };
Array Indexing :
array[index];
Size of array :
sizeof(array) / sizeof(type);
Ex :
int num[] = { 1, 2, 3, 4, 5 };
int n = num[2];

int square_num[5];
int size = sizeof(square_num) / sizeof(int);
for (int i = 0; i < size; i++)
    square_num[i] = (i+1)*(i+1);

for(int i=0; i < size; i++)
    cout << square_num[i] << " ";
• Multi-dimensional Arrays :

A multi-dimensional array is an array of arrays.

Syntax :
type name[size1][size2]...[sizeN];
Ex :
int arr[4][2] = { {1,2}, {3,4}, {5,6}, {7,8} };
for( int i=0; i<4; i++)
    for( int j=0; j<2; j++)
        cout << arr[i][j] << " ";
• Pointer to Array :
int num[5] = { 1, 2, 3, 4, 5};
int *p;
p = num;

cout << "Array values using pointer:" << endl;
for ( int i = 0; i < 5; i++ )
    cout << *(p + i) << endl;

cout << "Array values using num as address:" << endl;
for ( int i = 0; i < 5; i++ )
    cout << *(num + i) << endl;

cout << "Array values by incrementing pointer address:" << endl;
for ( int i = 0; i < 5; i++ )
    cout << *(p++) << endl;
• Passing Arrays to Function :
int sumOfNum(int num[], int size){
    int sum=0;
    for (int i=0; i < size; i++){
        sum += num[i];
    }
    return sum;
}

int main(){
    int num[5] = { 1, 2, 3, 4, 5};
    int size = sizeof(num)/sizeof(int);
    cout << "Sum of numbers is " << sumOfNum(num,size) << endl;

    return 0;
}
• Return Array from Function :
#include<iostream>
#include<time.h>
using namespace std;

// Get array of random numbers -
int* getArray(){
    static int num[5];

    // set the seed
    srand((unsigned)time(NULL));

    for (int i = 0; i < 5; i++)
        num[i] = rand()%10;

    return num;
}

int main(){
    int *p;
    p = getArray();
    for (int i = 0; i < 5; i++)
        cout << *(p++) << " ";

    return 0;
}
• Array of Objects :
class Employee {
    private:
        int id;
        string name;
    public:
        void setEmpID(int id){
            this->id = id;
        }
        int getEmpID(){
            return id;
        }
        void setEmpName(string name){
            this->name = name;
        }
        string getEmpName(){
            return name;
        }
};

int main(){
    // Creating array of type class:
    Employee emp[4];

    string emp_name[4] = {"Vinit", "Amit", "Ankit", "Sumit"};

    for(int i=0; i<4; i++){
        emp[i].setEmpID(i+101);
        emp[i].setEmpName(emp_name[i]);
    }

    for(int i=0; i<4; i++){
        cout << "\nEmployee ID: " << emp[i].getEmpID() << endl;
        cout << "Employee Name: " << emp[i].getEmpName() << endl;
    }

    return 0;
}
Array of Objects with Parameterized Constructor :
class Employee {
    private:
        int id;
        string name;
    public:
        Employee(int id, string name){
            this->id = id;
            this->name = name;
        }
        int getEmpID(){
            return id;
        }
        string getEmpName(){
            return name;
        }
};

int main(){
    // Creating array of type class with constructor:
    Employee emp[4] = { Employee(101,"Vinit"), Employee(102,"Amit"), Employee(103,"Sumit"), Employee(104,"Ankit") };

    for(int i=0; i<4; i++){
        cout << "\nEmployee ID: " << emp[i].getEmpID() << endl;
        cout << "Employee Name: " << emp[i].getEmpName() << endl;
    }

    return 0;
}
Dynamic Array of Objects using new Keyword :
class Employee {
    private:
        int id;
        string name;
    public:
        void setEmpID(int id){
            this->id = id;
        }
        int getEmpID(){
            return id;
        }
        void setEmpName(string name){
            this->name = name;
        }
        string getEmpName(){
            return name;
        }
};

int main(){
    // Creating dynamic array of type class:
    Employee* emp = new Employee[4];

    string emp_name[4] = {"Vinit", "Amit", "Ankit", "Sumit"};

    for(int i=0; i<4; i++){
        emp[i].setEmpID(i+101);
        emp[i].setEmpName(emp_name[i]);
    }

    for(int i=0; i<4; i++){
        cout << "\nEmployee ID: " << emp[i].getEmpID() << endl;
        cout << "Employee Name: " << emp[i].getEmpName() << endl;
    }

    return 0;
}

# Pointers

A pointer is a variable which holds the memory address of another variable, i.e., it stores the address of a memory location.

Syntax :
type *name;
Ex :
int n = 22;
// Referencing:
int *p = &n;

cout << "Adrress: " << p;
// Dereferencing:
cout << "\nValue: " << *p;
• Pointer to Pointer :

A pointer to a pointer is a form of multiple indirection or a chain of pointers where pointer contains the adress of another pointer.

Syntax :
type **name;
Ex :
int n = 22;
int *p = &n;
int **pp = &p;

cout << "n = " << n << endl;
cout << "p = " << *p << endl;
cout << "pp = " << **pp << endl;
Types of Pointers :
  • NULL Pointer :

    A pointer that is assigned NULL is called a null pointer. It does not point to any memory location; it represents an invalid memory location. It is used to initialise a pointer when that pointer has not been assigned any valid address yet.

    int *p = NULL;
  • Void Pointer :

    A pointer with no associated data type is referred to as a void pointer. It can point to data of any type. We cannot directly dereference a void pointer; it must first be typecast before dereferencing.

    int n = 22;
    void *p = &n;
    cout << *(int*)p << endl;
  • Wild Pointer :

    Wild pointers are also known as uninitialized pointers. These pointers usually point to some arbitrary memory location and may cause the program to crash or misbehave.

  • Dangling Pointer :

    A dangling pointer is a pointer that points to some non-existing memory location.

# References

A reference variable is an alias, that is, another name for an already existing variable.

Syntax :
type &name = var;
Ex :
string food = "Veg Rice";
string &meal = food;

# Functions

Functions are blocks of statements that perform a specific task. It is reusable code that can be called anywhere in the program.

Syntax :
Function Declaration (prototype) :
return_type functionName(parameter_list);
Function Definition :
return_type functionName(){
    // body of function
}
Function Calling :
functionName();
Ex :
// Function declaration:
void greet();
int sum(int, int);

// Function definition:
void greet(){
    cout << "Hello World";
}
int sum(int a, int b){
    return a+b;
}

int main(){
    // Calling function:
    greet();
    sum(17,22);

    return 0;
}
• Return Values :

A function with a return type other than void returns a value.

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

int main(){
    cout << "Addition is " << sum(1,2) << endl;
    return 0;
}
• Parameters vs Arguments :

When a function is called, the values that are passed in the call are called arguments. They are also called actual parameters. The values that are written at the time of the function prototype and the definition of the function are called parameters. They are also called formal parameters.

// Here name is parameter
void greet(string name){
    cout << "Hello " << name << endl;
}

int main(){
    string name = "Mandar";

    // Here name is argument
    greet(name);

    return 0;
}
• Function Arguments :

Arguments are passed to functions as formal parameters while calling the function. There are three ways in which we can pass parameters to a function.

  1. Call by Value :

    This method copies the actual value of an argument into the formal parameter of the function. In this case, changes made to the parameter inside the function have no effect on the argument.

    void swap(int a, int b){
        a = a + b;
        b = a - b;
        a = a - b;
    }
    int main(){
        int a=17, b=22;
        cout << "Before Swapping :\nA = " << a << "\nB = " << b << endl;
        swap(a, b);
        cout << "After Swapping :\nA = " << a << "\nB = " << b << endl;
    
        return 0;
    }
  2. Call by Pointer :

    This method copies the address of an argument into the formal parameter. Inside the function, the address is used to access the actual argument used in the call. This means that changes made to the parameter affect the argument.

    void swap(int *a, int *b){
        *a = *a + *b;
        *b = *a - *b;
        *a = *a - *b;
    }
    int main(){
        int a=17, b=22;
        cout << "Before Swapping :\nA = " << a << "\nB = " << b << endl;
        swap(&a, &b);
        cout << "After Swapping :\nA = " << a << "\nB = " << b << endl;
    
        return 0;
    }
  3. Call by Reference :

    This method copies the reference of an argument into the formal parameter. Inside the function, the reference is used to access the actual argument used in the call. This means that changes made to the parameter affect the argument.

    void swap(int &a, int &b){
        a = a + b;
        b = a - b;
        a = a - b;
    }
    int main(){
        int a=17, b=22;
        cout << "Before Swapping :\nA = " << a << "\nB = " << b << endl;
        swap(a, b);
        cout << "After Swapping :\nA = " << a << "\nB = " << b << endl;
    
        return 0;
    }
• Default Values for Parameters :

When no parameters are passed or some arguments are left blank while calling the function, the default values are used.

int sum(int a=2, int b=9){
    return a+b;
}
int main(){
    cout << "Sum is " << sum(1,2);
    cout << "\nSum is " << sum(22);
    cout << "\nSum is " << sum();

    return 0;
}
• Function Overloading :

Function overloading is a feature of object-oriented programming. When two or more functions have the same name but different numbers and types of parameters, the corresponding function is overloaded based on the parameters; this is called function overloading. This is an example of a compile-time polymorphism.

void sum(){
    int a, b;
    cout << "\nEnter Two Numbers : ";
    cin >> a >> b;
    cout << "Sum is " << a+b;
}
int sum(int a, int b){
    return a+b;
}
int sum(int a, int b, int c){
    return a+b+c;
}
float sum(float a, float b){
    return a+b;
}

int main(){
    cout << "Sum is " << sum(2,9);
    cout << "\nSum is " << sum(1,2,3);
    cout << "\nSum is " << sum(3.2f,2.4f);
    sum();

    return 0;
}
• Recursion :

The process in which a function calls itself directly or indirectly is called recursion, and the corresponding function is called a recursive function.

int sum(int n){
    if(n != 0) return n + sum(n-1);
    else return n;
}

int main(){
    cout << "Sum is " << sum(10);

    return 0;
}
• Inline Function :

In an inline function, when it is called, the whole code of the inline function gets inserted or substituted at the point of the inline function call by the compiler. Inlining is only a request to the compiler, not a command, and the compiler may ignore the request for inlining.

inline int max(int a, int b){
    return (a > b) ? a : b;
}

int main(){
    cout << "Max of number is " << max(12,10) << endl;
    return 0;
}
• Functions vs Methods :

A function is defined without any class and is called by its name only. A method also works the same as that of a function, but it is defined inside a class and invoked by its reference or object only.

class Name {
    public:
        // printm is method
        void printm(string name){
            cout << name << endl;
        }
};

// printf is function
void printf(string name){
    cout << name << endl;
}

int main(){
    Name ob;
    // printm is method
    ob.printm("Mandar");

    // printf is function
    printf("Patkar");

    return 0;
}

# Enumeration

An enumeration is a user-defined data type that consists of integral constants. Default values are 0, 1, 2, and so on. To define an enumeration, the keyword enum is used.

Syntax :
enum EnumName { list_of_names } var_list;
Ex :
enum Week { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday };

enum Color { Red, Green, Blue };

int main(){
    Week day;
    day = Monday;
    cout << "Day is " << day << endl;

    Color clr = Blue;
    cout << "Color is " << clr << endl;
    
    return 0;
}

# Structures

Structures (also called structs) are a way to group several related variables into one place. Each variable in the structure is referred to as a member of the structure. A structure can contain many different data types (int, string, bool, etc.). To access members of a structure, the member access operator (.) is used. We can't assign a character array (a string) to a structure, but we can copy it.

Syntax :
struct Name {
    type name;
    type name;
    ....;
} var;
Ex :
#include <iostream>
#include <cstring>
using namespace std;

struct Books {
    int book_id;
    char title[50];
    char author[50];
} book1;

int main(){
    // Book 1 Specification:
    book1.book_id = 01;
    strcpy( book1.title, "The C++ Programming Language");
    strcpy( book1.author, "Bjarne Stroustrup");
    cout << "Title: " << book1.title << endl;
    cout << "Author: " << book1.author << endl;

    // Book 2 Specification: (short-hand syntax)
    struct Books book2 = { 02, "Beginning C++ Programming", "Richard Grimes"}; 
    cout << "Title: " << book2.title << endl;
    cout << "Author: " << book2.author << endl;

    return 0;
}
• Self Referential Structure :

Self-referential structures are those structures in which one or more pointers point to another structure of the same type.

Syntax :
struct Name {
    int p;
    struct Name *pointer;
};
Ex :
struct Classroom {
    int roll;
    char name[10];
    struct Classroom *ptr;
};

int main(){
    struct Classroom c1 = { 22, "Mandar", NULL };

    c1.ptr = &c1;
    cout << "Roll: " << c1.ptr->roll << "\nName: "<< c1.ptr->name;

    return 0;
}
• Passing Structure as Function Argument :
struct Classroom {
    int roll;
    char name[10];
};

void print(struct Classroom c){
    cout << "Roll: " << c.roll << endl;
    cout << "Name: "<< c.name << endl;
}

int main(){
    struct Classroom c1 = {22, "Mandar"};
    print(c1);

    return 0;
}
• Passing Array of Structures as Argument :
struct Classroom {
    int roll;
    char name[10];
};

void print(struct Classroom c[]){
    for (int i=0; i<2; i++){
        cout << "Roll: " << c[i].roll << endl;
        cout << "Name: "<< c[i].name << endl;
    }
}

int main(){
    struct Classroom c[2] = { {17, "Vinit"}, {22, "Vinita"} };
    print(c);

    return 0;
}
• Return Structure Variable :
struct Classroom {
    int roll;
    char name[10];
};

struct Classroom edit(struct Classroom c){
    c.roll=22;
    strcpy(c.name,"Vinita");
    
    return c;
}

void print(struct Classroom c){
    cout << "Roll: " << c.roll << "\nName: "<< c.name << endl;
}

int main(){
    struct Classroom c1 = {17, "Vinit"};
    print(c1);

    c1=edit(c1);
    print(c1);

    return 0;
}
• Passing Pointer to Structure as Argument :
struct Classroom {
    int roll;
    char name[10];
};

void print(struct Classroom *c_ptr){
    cout << "Roll: " << c_ptr->roll << endl;
    cout << "Name: "<< c_ptr->name << endl;
}

int main(){
    struct Classroom c1 = {22, "Mandar"};
    print(&c1);

    return 0;
}

# Class & Objects

• Class :

A class is a blueprint or template for creating objects that define a set of properties and methods that are common to all objects of that type. It serves as a blueprint that defines the characteristics and behaviours of objects.

class Student {
    private:
        // Fields :
        int roll = 22;
        string name = "Mandar";

    public:
        // Methods :
        int printRoll(){
            return roll;
        }
        string printName(){
            return name;
        }
        void studentInfo();
};
Scope Resolution Operator :

Method definition outside class using the scope resolution operator (::).

void Student::studentInfo(){
    cout << "Roll : " << printRoll() << endl;
    cout << "Name : " << printName() << endl;
}
• Objects :

An object is an instance of a class that encapsulates data and behaviour. An object is created from a class blueprint and can be used to access the properties and methods defined in the class. When a class is defined, no memory is allocated, but when it is instantiated (i.e., an object is created), memory is allocated.

// Creating Object :
Student s1;

// Calling method with Objects :
s1.studentInfo();
Pointer to Object :
// Creating object:
Student s1;

// Creating pointer object:
Student *p_ob;
p_ob = &s1;

// Calling method with pointer object:
p_ob->studentInfo();
• Access Specifiers :

Access specifiers define how the members (attributes and methods) of a class can be accessed. Default access specifier is private.

  • public: members are accessible from outside the class.
  • protected: members cannot be accessed from outside the class; however, they can be accessed in inherited classes.
  • private: members cannot be accessed (or viewed) from outside the class.
class MyClass {
    public: // Public access specifier
        int pu;
    protected: // Protected access specifier
        int pt;
    private: // Private access specifier
        int pr;
};

int main(){
    MyClass ob;
    ob.pu = 25; // Allowed (public)
    ob.pt = 75; // Error: Not allowed (protected)
    ob.pr = 50; // Error: Not allowed (private)

    return 0;
}
• This Keyword :

The keyword this is a pointer that refers to the current instance of the class. The compiler supplies this pointer implicitly along with the names of functions. It is passed as a hidden argument to all non-static member function calls and is available as a local variable within the body of all non-static functions.

class Student {
    private:
        int roll;
        string name;

    public:
        // Constructor :
        Student(int roll, string name){
            this->roll = roll;
            this->name = name;
        }

        void studentInfo(){
            cout << "Roll : " << roll << endl;
            cout << "Name : " << name << endl;
        }

        void print(){
            this->studentInfo();
        }
};

int main(){
    Student s1(22, "Mandar");
    s1.print();
    
    return 0;
}
• Static Members :

When a variable or method is declared static, a single copy of the variable is created (memory is allocated only once) and shared among all objects at the class level. All instances of the class share the same static variable. The static is a property of the class, not the object, and hence the object of the class can't use it to access it; it can be called using the class name. The value of static variables and data members persists until the end of the program.

Static Variable :
class MyClass {
    public:
        // static variable :
        static int count;

        MyClass(){
            count++;
        }

        void printCount(){
            cout << count << " objects created" << endl;
        }
};

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

int main(){
    MyClass ob1, ob2;
    ob1.printCount();

    MyClass ob3;
    ob3.printCount();

    MyClass ob4, ob5;
    cout << "Total objects : " << MyClass::count << endl;

    return 0;
}
Static Method :
class MyClass {
    public:
        // static variable :
        static int count;

        MyClass(){
            count++;
        }

        static void printCount(){
            cout << count << " objects created" << endl;
        }
};

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

int main(){
    MyClass ob1;
    MyClass::printCount();

    MyClass ob2, ob3;
    MyClass::printCount();

    return 0;
}
• Friend Class & Function :

A friend class or function can access the private and protected members of a class. It is declared using the friend keyword inside the body of the class. A friend function can be a member of another class or a global function.

Syntax :
class ClassName {
    friend return_type functionName(arguments);
}
Friend Class :
class Student {
    private:
        int roll;
        string name;
    public:
        // Constructor :
        Student(int roll, string name){
            this->roll = roll;
            this->name = name;
        }

    friend class Info;
};

class Info {
    public:
        void studentInfo(){
            Student s(22, "Mandar");
            cout << "Roll : " << s.roll << endl;
            cout << "Name : " << s.name << endl;
        }
};

int main(){
    Info ob;
    ob.studentInfo();

    return 0;
}
Friend Function :
class B;

class A {
    private:
        int x;
    public:
        // Constructor :
        A() : x(10){}

    friend void addNum(A, B);
};

class B {
    private:
        int y;
    public:
        // Constructor :
        B() : y(20){}

    friend void addNum(A, B);
};

void addNum(A a, B b){
    cout << "Addition is " << a.x + b.y << endl;
}

int main(){
    A a;
    B b;
    addNum(a,b);

    return 0;
}

# Constructor & Destructor

• Constructor :

It is a special method that is automatically called when an object of a class is created. The constructor has the same name as the class, it is always public, and it does not have any return value.

class Student {
    private:
        int roll;
        string name;

    public:
        // Constructor (parameterized) :
        Student(int r, string n){
            cout << "Constructor is called" << endl;
            roll = r;
            name = n;
        }

        void studentInfo(){
            cout << "Roll : " << roll << endl;
            cout << "Name : " << name << endl;
        }
};

int main(){
    Student s1(22, "Mandar");
    s1.studentInfo();

    return 0;
}
• Copy Constructor :

The copy constructor is a constructor that creates an object by initialising it with an already created object of the same class. The copy constructor takes a reference to an object of the same class as an argument. There will always be only one copy constructor which can be either defined by the user or the compiler. The compiler implicitly defines the default copy constructor if it is not defined by the programmer.

class Student {
    private:
        int roll;
        string name;

    public:
        // Constructor :
        Student(int r, string n){
            roll = r;
            name = n;
        }

        // User Defined Copy Constructor (explicitly defined) :
        Student(const Student &s){
            roll = s.roll;
            name = s.name;
        }

        void studentInfo(){
            cout << "Roll : " << roll << endl;
            cout << "Name : " << name << endl;
        }
};

int main(){
    Student s1(22, "Mandar");
    s1.studentInfo();

    // Copy Constructor :
    Student s2=s1;
    s2.studentInfo();

    Student s3(s2);
    s3.studentInfo();

    return 0;
}
• Initialization List :

The initialization lists are used to initialise fields.

class Student {
    private:
        int roll;
        string name;
        int std;

    public:
        // Constructor: Initialization List :
        Student(int r, string n, int s): name(n), std(s){
            roll = r;
        }

        void studentInfo(){
            cout << "Roll : " << roll << endl;
            cout << "Name : " << name << endl;
            cout << "Std : " << std << "th" << endl;
        }
};

int main(){
    Student s1(22, "Mandar", 9);
    s1.studentInfo();

    return 0;
}
Initialization List in Inheritance :
class School {
    private:
        string sch_name;
    public:
        School(string name) : sch_name(name) {}

        string schoolName(){
            return sch_name;
        }
};

class Student : public School {
    private:
        int roll;
        string name;
        int std;

    public:
        // Constructor: Initialization List :
        Student(string sch_name, int r, string n, int s): School(sch_name), name(n), std(s){
            roll = r;
        }

        void studentInfo(){
            cout << "School : " << schoolName() << endl;
            cout << "Roll : " << roll << endl;
            cout << "Name : " << name << endl;
            cout << "Std : " << std << "th" << endl;
        }
};

int main(){
    Student s1("Vartak", 22, "Mandar", 9);
    s1.studentInfo();

    return 0;
}
• Destructor :

It is a special method that is automatically called when an object of its class goes out of scope. The destructor has the same name as the class, is preceded by a tilde (~) symbol, is always public, and does not have any return value.

class Student {
    private:
        int roll;
        string name;

    public:
        // Constructor :
        Student(int r, string n){
            cout << "Constructor is called" << endl;
            roll = r;
            name = n;
        }

        void studentInfo(){
            cout << "Roll : " << roll << endl;
            cout << "Name : " << name << endl;
        }

        // Destructor :
        ~Student(){
            cout << "Destructor is called" << endl;
        }
};

int main(){
    Student s1(22, "Mandar");
    s1.studentInfo();

    return 0;
}

# Inheritance

Inheritance is a feature or a process in which new classes are created from existing ones. The new class created is called a "derived class" or "child class," and the existing class is known as the "base class" or "parent class." The derived class is now said to be inherited from the base class. The inherited class acquires all the properties and behaviours of the parent class. This allows programmers to reuse, extend, or modify the attributes and behaviours of existing classes. The private members of the base class are never inherited.

• Visibility of Inherited Members :
Base Class Visibility Derived Class Visibility
Public Private Protected
Public Public Private Protected
Protected Protected Private Protected
Private Not Inherited Not Inherited Not Inherited
C++ supports five types of inheritance :
  1. Single Inheritance
  2. Multiple Inheritance
  3. Multilevel Inheritance
  4. Hierarchical Inheritance
  5. Hybrid Inheritance
1. Single Inheritance :

Single inheritance is defined as the inheritance in which a derived class is inherited from only one base class.

// Base or Parent Class :
class Bank {
    private:
        string bank_name;
    public:
        Bank(string bank) : bank_name(bank) {}
        string printBank(){
            return bank_name;
        }
};

// Derived or Child Class :
class Account : public Bank {
    private:
        string type;
        int num;
    public:
        Account(string bank, string type, int num) : Bank(bank), type(type), num(num) {}
        string printAccountType(){
            return type;
        }
        int printAccountNum(){
            return num;
        }
};

int main(){
    Account person1("SBI","Saving",1234);

    cout << "Bank : " << person1.printBank() << endl;
    cout << "Account Type : " << person1.printAccountType() << endl;
    cout << "Account Number : " << person1.printAccountNum() << endl;

    return 0;
}
2. Multiple Inheritance :

Multiple inheritance is defined as the inheritance in which a derived class is inherited from two or more base classes.

// Base Class 1 :
class Father {
    private:
        string fname = "Vinit Patil";
    public:
        string printFName(){
            return fname;
        }
};

// Base Class 2 :
class Mother {
    private:
        string mname = "Vinita Patil";
    public:
        string printMName(){
            return mname;
        }
};

// Derived Class :
class Son : public Father, public Mother {
    private:
        string sname = "Amit Patil";
    public:
        string printSName(){
            return sname;
        }
};

int main(){
    Son s1;

    cout << "Name : " << s1.printSName() << endl;
    cout << "Father Name : " << s1.printFName() << endl;
    cout << "Mother Name : " << s1.printFName() << endl;

    return 0;
}
Ambiguity in Inheritance :

In multiple inheritances, when one class is derived from two or more base classes, there may be a possibility that the base classes have functions with the same name, and the derived class may not have functions with the same name as those of its base classes. If the derived class object needs to access one of the similarly named member functions of the base classes then it results in ambiguity because the compiler gets confused about which base’s class member function should be called. To solve this ambiguity scope resolution operator (::) is used.

Syntax :
objectName.ClassName::functionName();
Ex :
// Base Class 1 :
class Father {
    private:
        string fname = "Vinit Patil";
    public:
        string printName(){
            return fname;
        }
};

// Base Class 2 :
class Mother {
    private:
        string mname = "Vinita Patil";
    public:
        string printName(){
            return mname;
        }
};

// Derived Class :
class Son : public Father, public Mother {
    private:
        string sname = "Amit Patil";
    public:
        string printSName(){
            return sname;
        }
};

int main(){
    Son s1;

    cout << "Name : " << s1.printSName() << endl;

    // Resolve ambiguity using scope resolution operator :
    cout << "Father Name : " << s1.Father::printName() << endl;
    cout << "Mother Name : " << s1.Mother::printName() << endl;

    return 0;
}
3. Multilevel Inheritance :

Multilevel inheritance is defined as the inheritance in which a derived class is inherited from another derived class.

// Base Class :
class GrandFather {
    public:
        int age_g;
        GrandFather(int g) : age_g(g) {}
        string gname = "Avnish Patil";
        string printGName(){
            return gname;
        }
};

// Derived & Base Class :
class Father : public GrandFather {
    public:
        int age_f;
        Father(int g, int f) : GrandFather(g), age_f(f) {}
        string fname = "Vinit Patil";
        string printFName(){
            return fname;
        }
};

// Derived Class :
class Son : public Father {
    public:
        int age_s;
        Son(int g, int f, int s) : Father(g,f), age_s(s) {}
        string sname = "Amit Patil";
        string printSName(){
            return sname;
        }
};

int main(){
    Son s1(95,75,30);

    cout << "I am " << s1.printSName() << " my age is " << s1.age_s << endl;
    cout << "My father name is " << s1.printFName() << " his age is " << s1.age_f << endl;
    cout << "My grand father name is " << s1.printGName() << " his age is " << s1.age_g << endl;

    return 0;
}
4. Hierarchical Inheritance :

Hierarchical inheritance is defined as the type of inheritance in which more than one derived class is inherited from only one base class.

// Base Class :
class Father {
    private:
        string fname = "Vinit Patil";
    public:
        string printFName(){
            return fname;
        }
};

// Derived Class 1 :
class Son : public Father {
    private:
        string sname = "Amit Patil";
    public:
        string printSName(){
            return sname;
        }
};

// Derived Class 2 :
class Daughter : public Father {
    private:
        string dname = "Amita Patil";
    public:
        string printDName(){
            return dname;
        }
};

int main(){
    Son s1;
    cout << "Father Name : " << s1.printFName() << endl;
    cout << "Son Name : " << s1.printSName() << endl;

    Daughter d1;
    cout << "\nFather Name : " << d1.printFName() << endl;
    cout << "Daughter Name : " << d1.printDName() << endl;

    return 0;
}
5. Hybrid Inheritance :

Inheritance that combines multiple types of inheritance is known as hybrid inheritance.

class Shape {
    public:
        Shape(){
            cout << "This is Shape" << endl;
        }
};

class Circle : public Shape {
    public:
        Circle(){
            cout << "This is Circle" << endl;
        }
};

class Rectangle : public Shape {
    public:
        Rectangle(){
            cout << "This is Rectangle" << endl;
        }
};

class Square : public Rectangle {
    public:
        Square(){
            cout << "This is Square" << endl;
        }
};

int main(){
    // Single Inheritance : Shape -> Circle
    Circle c1;

    // Hierarchical Inheritance : Shape -> Circle & Rectangle
    Circle c2
    Rectangle r1;

    // Multilevel Inheritance : Shape -> Rectangle -> Square
    Square s1;

    return 0;
}
Virtual Inheritance :

Virtual inheritance is a C++ technique that ensures only one copy or instance of a base class's member variables should be present in the inheritance hierarchy, even if the class is inherited multiple times. This is done with the virtual keyword. Objects of class Cuboid have two paths to call constructor of class Shape; hence, it will result in ambiguity, called the "diamond problem." Virtual inheritance can be used to resolve this ambiguity in inheritance.

class Shape {
    public:
        Shape(){
            cout << "This is Shape" << endl;
        }
};

class Rectangle : virtual public Shape {
    public:
        Rectangle(){
            cout << "This is Rectangle" << endl;
        }
};

class Square : virtual public Rectangle {
    public:
        Square(){
            cout << "This is Square" << endl;
        }
};

class Cuboid : virtual public Rectangle, virtual public Square {
    public:
        Cuboid(){
            cout << "This is Cuboid" << endl;
        }
};

int main(){
    /*      Shape
            /   \
    Rectangle   Square
            \   /
            Cuboid
    */

    Cuboid cb;

    return 0;
}

# Polymorphism

The word "polymorphism" means having many forms. That is, the same entity (function or operator) behaves differently in different scenarios, so a single action can be performed in different ways.

Types of polymorphism :
  1. Compile-time Polymorphism
  2. Runtime Polymorphism
• Compile-time Polymorphism :

Compile-time polymorphism, also called static polymorphism, is resolved (which method to execute) during compile time and is achieved through method overloading and operator overloading. It is also called static binding or early binding. Binding is the association of names with classes. In the case of static binding, names can be associated with classes during compilation time.

1. Method Overloading :

Method overloading is a feature of object-oriented programming. When two or more methods have the same name but different numbers and types of parameters, the corresponding method is overloaded based on the parameters; this is called method overloading. This is an example of a compile-time polymorphism.

class Sum {
    public:
        void sum(){
            int a, b;
            cout << "\nEnter Two Numbers : ";
            cin >> a >> b;
            cout << "Sum is " << a+b << endl;
        }
        int sum(int a, int b){
            return a+b;
        }
        int sum(int a, int b, int c){
            return a+b+c;
        }
        float sum(float a, float b){
            return a+b;
        }
};

int main(){
    Sum s1;

    cout << "Sum is " << s1.sum(2,9);
    cout << "\nSum is " << s1.sum(1,2,3);
    cout << "\nSum is " << s1.sum(3.2f,2.4f);
    s1.sum();

    return 0;
}
2. Operator Overloading :

The C++ language has the ability to provide the operators with a special meaning for a data type; this ability is known as "operator overloading." Operators can be used for user-defined classes. It is an idea of giving special meaning to an existing operator in C++ without changing its original meaning.

Operators that cannot be overloaded :
  1. Scope Resolution (::)
  2. Member Selection (.)
  3. Member Selection through Pointer (.*)
  4. Ternary Operator (?:)
  5. Sizeof Operator (sizeof())
Types of operator overloading :
  • Unary Operator Overloading :

    The unary increment operator (++) is overloaded for incrementing objects.

    class OperatorOL {
        private:
            int count = 0;
        public:
            // Operator ++ overloaded :
            void operator ++ (){
                ++count;
            }
    
            int printCount(){
                return count;
            }
    };
    
    int main(){
        OperatorOL ob;
    
        while(ob.printCount() < 5)
            ++ob;
        
        cout << "Count = " << ob.printCount() << endl;
    
        return 0;
    }
  • Binary Operator Overloading :

    The binary addition operator (+) is overloaded for the addition of two objects.

    class Complex {
        private:
            int real, imag;
        public:
            Complex(int r, int i){
                real = r;
                imag = i;
            }
    
            void print(){
                cout << real << " + i" << imag << endl;
            }
    
            // Operator + overloaded :
            Complex operator + (const Complex& c2){
                Complex c3(0,0);
                c3.real = real + c2.real;
                c3.imag = imag + c2.imag;
    
                return c3;
            }
    };
    
    int main(){
        Complex c1(2,4), c2(3,5);
        Complex c3 = c1 + c2;
    
        c1.print();
        c2.print();
        c3.print();
    
        return 0;
    }
• Runtime Polymorphism :

Runtime polymorphism, also called dynamic polymorphism, is resolved during runtime and is achieved through method overriding and virtual functions. It is also called dyanamic binding or late binding, as the names can be associated with the classes during runtime.

1. Method Overriding :

Method overriding is defined as the redefinition of a base-class method in its derived class with the same signature, i.e., the same return type and parameters.

class Base {
    public:
        void print(){
            cout << "This is Base Class" << endl;
        }
};

class Derived : public Base {
    public:
        void print(){
            cout << "This is Derived Class" << endl;
        }
};

int main(){
    Derived ob;
    ob.print();

    // Access base class method :
    ob.Base::print();

    return 0;
}
2. Virtual Function :

The keyword virtual represents that method being overridden. A virtual function is a member function of a class, and it can be overridden in its derived class. Virtual functions cannot be static.

class Base {
    public:
        // Virtual Function :
        virtual void print(){
            cout << "This is Base Class - Virtual" << endl;
        }
        // Non-Virtual Function :
        void printN(){
            cout << "This is Base Class - Non Virtual" << endl;
        }
};

class Derived : public Base {
    public:
        void print(){
            cout << "This is Derived Class - Virtual" << endl;
        }
        void printN(){
            cout << "This is Derived Class - Non Virtual" << endl;
        }
};

int main(){
    Derived d;
    Base *bptr = &d;
  
    // Virtual function, binded at runtime :
    bptr->print();
  
    // Non-virtual function, binded at compile time :
    bptr->printN();

    return 0;
}
Identifier Override :

In C++, the override identifier is used to explicitly indicate that a virtual function in a derived class is intended to override a virtual function with the same name and signature in its base class.

class Shape {
    public:
        virtual void draw(){
            cout<<"Can not draw an unknown Shape!" << endl;
        }
};

class Rectangle : public Shape {
    public:
        void draw() override {
            cout << "Drawing Rectangle..." << endl;
        }
};

int main(){
    Rectangle rect;
    rect.draw();

    return 0;
}

# Abstract Classes

An abstract class is a class that cannot be instantiated but can be inherited to provide an interface or blueprint for other classes. An abstract class contains at least one pure virtual function. A pure virtual function (or abstract function) is one that can be overridden in the derived class but cannot be defined in its base class, as there is no meaningful definition you could give for the function in the base class. A virtual function can be declared "pure" by using the operator =0 at the end, indicating that it has no implementation and must be overridden by any class that inherits from it.
Any class that implements an abstract class must provide an implementation for all of the pure virtual functions declared in it. If the pure virtual function is not defined in its derived class, then the derived class also becomes an abstract class. Abstract classes can have both abstract and non-abstract methods. The non-abstract methods have a default implementation in the abstract class and can be used by the subclasses as is, or overridden if necessary.

// Abstract Class :
class Shape {
    public:
        // Non-Abstract Function :
        void print(){
            cout << "Inherating shape class..." << endl;
        }
        // Virtual Function :
        virtual void draw(){
            cout << "Drawing shape..." << endl;
        }
        // Pure Virtual Function :
        virtual void area() = 0;
};

class Rectangle : public Shape {
    private:
        int length, breadth;
    public:
        Rectangle(int l, int b){
            length = l;
            breadth = b;
        }
        void draw(){
            cout << "Drawing rectangle..." << endl;
        }
        void area(){
            cout << "Area of rectangle is " << length*breadth << endl;
        }
};

int main(){
    Rectangle r1(3,8);
    r1.print();
    r1.draw();
    r1.area();

    return 0;
}
• Interfaces :

An interface in object-oriented programming is a collection of abstract methods (methods without implementation) and constant variables. It provides a common set of methods that can be implemented by multiple classes. In C++, an interface is an abstract class that has only pure virtual functions.

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

class Rectangle : public Shape {
    private:
        int length, breadth;
    public:
        Rectangle(int l, int b){
            length = l;
            breadth = b;
        }
        void draw(){
            cout << "Drawing Rectangle..." << endl;
        }
        float area(){
            return length*breadth;
        }
};

class Circle : public Shape {
    private:
        int radius;
    public:
        Circle(int r){
            radius = r;
        }
        void draw(){
            cout << "Drawing Circle..." << endl;
        }
        float area(){
            return 3.14*radius*radius;
        }
};

int main(){
    // Rectangle:
    Rectangle r1(3,8);
    r1.draw();
    cout << "Area of rectangle is " << r1.area() << endl;

    // Circle:
    Circle c1(4);
    c1.draw();
    cout << "Area of circle is " << c1.area() << endl;

    return 0;
}

# Abstraction

Abstraction is a feature of OOP; it shows only the necessary details to the user by hiding the actual implementation. Abstraction in C++ is achieved through classes, header files, and access specifiers. It is implemented by using abstract classes and interfaces. In abstraction, problems are solved at the design or interface level. It avoids code duplication and increases code reusability. In a nutshell, abstraction hides implementation with the help of abstract classes and interfaces.

Types of abstraction :
class Employee {
    private:
        int ctc; // in LPA
    public:
        virtual string domain() = 0;
        void setCTC(int ctc){
            this->ctc = ctc;
        }
        int getCTC(){
            return ctc;
        }
        void employeeInfo(){
            cout << "Employee Domain: " << this->domain() << endl;
            cout << "Employee CTC: " << this->getCTC() << " LPA" << endl;
        }
};

class Sofware : public Employee {
    public:
        string domain(){
            return "Sofware Development";
        }
};

class Marketting : public Employee {
    public:
        string domain(){
            return "Marketting";
        }
};

int main(){
    // Software :
    Sofware eng;
    eng.setCTC(18);
    eng.employeeInfo();

    // Marketting :
    Marketting mrk;
    mrk.setCTC(15);
    mrk.employeeInfo();

    return 0;
}

# Encapsulation

The wrapping or binding of fields (state) and methods (behaviour) together into a single unit is called encapsulation. This keeps data safe from outside interference and misuse. Encapsulation means restricting direct access to certain components of an object so that users can’t access the state values for all variables and helps in data hiding. Encapsulation is implemented using an access modifier, i.e., private, protected, and public. During encapsulation, problems are solved at the implementation level. In a nutshell, encapsulation is hiding the data with the help of getter and setter.

Ex : Below is an example of data hiding using access modifiers.

In this program, the variable salary is made private so that it can be accessed and manipulated only by using the getter and setter methods that are present within the class. Therefore, we can say that the variable salary and the getter as well as setter methods have been bound together, which is nothing but encapsulation.

class Employee {
    private:
        int salary;
    public:
        // Setter :
        void setSalary(int sal){
            salary = sal;
        }
        // Getter :
        int getSalary(){
            return salary;
        }
};

int main(){
    Employee emp;
    emp.setSalary(80000);
    cout << "Salary is " << emp.getSalary() << endl;

    return 0;
}

# Exception Handling

An exception is an error that arises during the execution of a program. Exception handling is the process of handling errors at runtime so that the normal flow of a program can be maintained. C++ exception handling is built upon three keywords: try, catch, and throw.

Syntax :
try {
    // Block of code to try
} catch(Exceptions) {
    // Block of code to handle errors
}
Ex :
try {
    float x=5, y=0;
    if (y == 0)
        throw "Error: Division By Zero!";
    else
        cout << "Division is" << x/y;
} catch(const char *E) {
    cout << E << endl;
}
Catch All Types of Exceptions :
try {
    int age = 16;
    if (age >= 18)
        cout << "Access Granted" << endl;
    else
        throw 404;
} catch (...) {
    cout << "Access Denied! You must be at least 18 years old." << endl;
}
Multiple Catch Statements :
try {
    int age;
    cout << "Enter Age: ";
    cin >> age;
    if (age == 0)
        throw "Error: Age cannot be zero!";
    else if (age < 0)
        throw std::runtime_error("Runtime Error: Age cannot be negative!");
    else
        cout << "Your age is " << age << endl;
} catch (const char *E){
    cout << E << endl;
} catch (std::runtime_error& E){
    cout << E.what() << endl;
} catch (...){
    cout << "Unkwown Error!" << endl;
}
• User-Defined Exceptions :

The new exception can be defined by overriding and inheriting exception class functionality.

// User-Defined Error Class :
class ZeroDivisionError : public exception {
    public:
        const char* what() const throw () {
            return "Error: Attempted to divide by zero!";
        }
};

int main(){
    try {
        int x, y;
        cout << "Enter Two Numbers: ";
        cin >> x >> y;
        if (y == 0){
            throw ZeroDivisionError();
        }
        else
            cout << "Division is " << (float)x/y << endl;
    } catch (ZeroDivisionError& E){
        cout << E.what() << endl;
    }

    return 0;
}

# Files & Streams

A standard C++ library called fstream is used to read and write from a file.

Class Description
ifstream Reads from files
ofstream Creates and writes to files
fstream Creates, reads, and writes to files
• Read Operation :
#include<iostream>
#include<fstream>
using namespace std;

int main(){
    // Creating object of ifstream class:
    ifstream infile;

    // Opening file to read:
    infile.open("sample.txt",ios::in);

    // Reading file:
    string text;
    while(getline(infile,text))
        cout << text << endl;

    return 0;
}
File Modes :
Mode Flag Description
ios::app Append mode. All output to that file to be appended to the end
ios::ate Open a file for output and move the read/write control to the end of the file
ios::in Open a file for reading
ios::out Open a file for writing
ios::trunc If the file already exists, its contents will be truncated before opening the file
• Write Operation :
#include<iostream>
#include<fstream>
using namespace std;

int main(){
    // Crearing file:
    ofstream outfile("sample.txt");

    // Write to the file:
    outfile << "I am learning C++\n";
    outfile << "C++ is the fast and efficient language.";

    // Closing file:
    outfile.close();

    return 0;
}
• Read-Write Operation :
#include<iostream>
#include<fstream>
using namespace std;

int main(){
    string fname;
    char lname[20];

    // User Input:
    cout << "Enter First Name: ";
    getline(cin,fname); // Receive string
    cout << "Enter Last  Name: ";
    cin.getline(lname, 20); // Receive char array

    // Writing file:
    ofstream outfile;
    outfile.open("name.txt");
    outfile << fname+" "+lname;
    outfile.close();

    // Reading file:
    ifstream infile;
    infile.open("name.txt");
    string line;
    while(getline(infile,line))
        cout << line << endl;
    infile.close();

    return 0;
}
• Function getline() :

It is a pre-defined function defined in the <string.h> header file that is used to accept a line or a string from the input stream until the delimiting character is encountered. The cin is an object that is used to take input from the user but does not allow the user to take the input in multiple lines. To accept the multiple lines, we use the getline() function.

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

int main(){
    string name;
    cout << "Enter Full Name: ";
    cin >> name;
    cout << name << endl;
    cin.ignore();

    cout << "Enter : ";
    getline(cin, name);
    cout << name << endl;

    return 0;
}

# Dynamic Memory

Memory allocated during runtime is called dynamic memory, and the process of allocating memory at the time of execution is called dynamic memory allocation. C++ allows us to allocate the memory at run time. This is known as dynamic memory allocation. In C++, the memory is allocated and then deallocated dynamically using the new and delete operators.

Ex :
// Addition of two integers using dyanamic memory:
int *p_a, *p_b;
p_a = new int;
p_b = new int;

cout << "Enter Two Numbers: ";
cin >> *p_a >> *p_b;

cout << "Addition is " << *p_a+*p_b << endl;

delete p_a, p_b;
Memory allocation for the arrays :
// Addition of 5 integers (array) using dyanamic memory:
int sum = 0;
int *p_arr;
p_arr = new int[5];

cout << "Enter 5 Numbers: ";
for(int i=0; i<5; i++){
    cin >> *(p_arr+i);
    sum += *(p_arr+i);
}

cout << "Addition is " << sum << endl;

delete[] p_arr;
Memory allocation for the objects :
class Sum {
    public:
        int a, b;
        Sum(int a, int b){
            this->a = a;
            this->b = b;
        }
        void sum(){
            cout << "Addition is " << a+b << endl;
        }
};

int main(){
    Sum *p_sm = new Sum(22,17);
    p_sm->sum();

    delete p_sm;

    return 0;
}

# Templates

Templates are the foundation of generic programming, which involves writing code in a way that is independent of any particular type. A template is a blueprint or formula for creating a generic class or function. The library containers like iterators and algorithms are examples of generic programming and have been developed using the template concept.

There are two ways we can implement templates:
  1. Function Template
  2. Class Template
• Function Template :

Generic functions use the concept of a function template. Generic functions define a set of operations that can be applied to various types of data. The type of data that the function will operate on depends on the type of data passed as a parameter. A generic function is created by using the keyword template.

Syntax :

The type is only a placeholder for the data type, which the compiler will automatically replace with the actual data type. It is used within the function definition. And typename is a keyword.

template <typename type>
return_type functionName(parameters_list){
    // body of function
}
Ex :
// Function Template:
template <typename T>
T maxn(T a, T b){
    return a > b ? a : b;
}

int main(){
    cout << maxn(2,4) << endl; // for int:
    cout << maxn<int>(4,8) << endl;
    cout << maxn(5.5,4.25) << endl; // for float:
    cout << maxn("hello","world") << endl; // for string:

    return 0;
}
Function Template with Multiple Parameters :
template <typename T1, typename T2>
float add(T1 a, T2 b){
    return a+b;
}

int main(){
    cout << add(2,4) << endl; // for int
    cout << add(20.25,10) << endl; // for float & int

    return 0;
}
Function Template Overloading :
template <typename T1, typename T2>
float add(T1 a, T2 b){
    return a+b;
}

template <typename T1, typename T2, typename T3>
float add(T1 a, T2 b, T3 c){
    return (a > b) ? (a > c ? a : c) : (b > c ? b : c);
}

int main(){
    cout << add(2,4) << endl;
    cout << add(20.25,10) << endl;
    cout << add(2,4,6) << endl;
    cout << add(10,12.5,12) << endl;

    return 0;
}
• Class Template :

When a class uses the concept of a template, then the class is known as a generic class. A class template starts with the keyword template, followed by the template parameter(s) inside <>, which is followed by the class declaration.

Syntax :
template <typename type>
class ClassName {
    // Class Definition
}
Ex :
// Class Template:
template <typename T>
class Generic {
    private:
        T num1, num2;
    public:
        Generic(T n1, T n2){
            num1 = n1;
            num2 = n2;
        }
        T add(){
            return num1+num2;
        }
};

int main(){
    Generic<int> obi(2,4);
    cout << obi.add() << endl;

    Generic<float> obf(2.5,4.5);
    cout << obf.add() << endl;

    return 0;
}
Class Template with Multiple Parameters :
template <typename T1, typename T2>
class Generic {
    private:
        T1 num1;
        T2 num2;
    public:
        Generic(T1 n1, T2 n2){
            num1 = n1;
            num2 = n2;
        }
        float add(){
            return num1+num2;
        }
};

int main(){
    Generic<int,int> ob(2,4);
    cout << ob.add() << endl;

    Generic<float,int> ob2(2.5,2);
    cout << ob2.add() << endl;

    return 0;
}

# Namespaces

A namespace is a collection of related names or identifiers (such as variables, functions, classes, etc.) under a single name. It helps to separate identifiers with the same name in other namespaces or the global namespace. A namespace defines a scope. A namespace definition begins with the keyword namespace, followed by the namespace name. To call the namespace-enabled version of either function or variable, prepend the scope resolution operator (::) and the namespace name. Namespaces can be nested.

#include<iostream>
using namespace std;

// Namespace integers :
namespace integers {
    int add(int a, int b){
        return a+b;
    }
}

// Namespace floats :
namespace floats {
    float add(float a, float b){
        return a+b;
    }
}

int main(){
    // Integer addition:
    cout << integers::add(5,10) << endl;

    // Float addition:
    cout << floats::add(5.20,15.25) << endl;

    return 0;
}
• Using Directive :

The prepending of namespaces can be avoided by the using namespace directive. This directive tells the compiler that the subsequent code is making use of names in the specified namespace.

#include<iostream>>
using namespace std;

namespace morning {
    void greet(){
        cout << "Good Morning!" << endl;
    }
}

namespace evening {
    void greet(){
        cout << "Good Evening!" << endl;
    }
}

using namespace morning;

int main(){
    greet();

    return 0;
}
• Discontiguous Namespaces :

A namespace can be defined in several parts, and a namespace is made up of the sum of its separately defined parts. The separate parts of a namespace can be spread over multiple files. The following namespace definition either defines a new namespace or adds new elements to an existing one.

namespace integers {
    int subtract(int a, int b){
        return a-b;
    }
}

# Preprocessor

The preprocessors are the directives, which give instructions to the compiler to preprocess the information before actual compilation starts. The preprocessor directives are preceded by a hash sign (#), and no semicolon (;) is expected at the end of a preprocessor directive as it is not a program statement.

Types of preprocessor directives:
• Macros :

A macro is a piece of code that is defined using the #define directive, and it is replaced with its corresponding value at compile time. The #define directive is used to define the preprocessor macro by creating symbolic constants, and the #undef directive is used to undefine the macro.

Syntax :
// Define Macro :
#define identifier replacement

// Undefine Macro :
#undef identifier
Ex :
#include<iostream>
using namespace std;

// Define macro :
#define PI 3.14159
#define NEWLINE '\n'
#define MAX(a,b) (a > b ? a : b)

int main(){
    cout << "Value of Pi = " << PI << NEWLINE;

    cout << "Max NO = " << MAX(10,25) << NEWLINE;

    return 0;
}
Predefined C++ Macros :
Macro Description
__LINE__ current line number of program when it is being compiled
__FILE__ current file name of program when it is being compiled
__DATE__ date of the translation of source file into object code as a string (format: month day year)
__TIME__ time at which program was compiled as a string (format: hh:mm:ss)
Ex :
cout << "Line : " << __LINE__ << endl;
cout << "FILE : " << __FILE__ << endl;
cout << "DATE : " << __DATE__ << endl;
cout << "TIME : " << __TIME__ << endl;
• File Inclusion :

A file inclusion directive (#include) is a preprocessor directive that tells the compiler to include the contents of another file in the source code program. There are two types of files that can be included by the user in the program:

  • Header Files or Standard Library : These files contain definitions of pre-defined functions that are built into the C++ language.

    Syntax :
    #include <file_name>
  • User-Defined Files : When a program becomes very large and complex, it is a good practice to divide it into smaller files and include them whenever needed. These types of files are user-defined files.

    Syntax :
    #include "file_name"
• Conditional Compilation :
Directive Description
#ifdef MACRO check whether MACRO is defined by #define or not
#ifndef MACRO check whether MACRO is not defined by #define
#endif terminate macro condition
#if [condition] check whether condition is true (similar to if statement)
#else code to execute when condition is false
#elif [condition] similar to else-if statement
Syntax :
#ifdef MACRO
    // true_if_macro_defined
#endif
Ex : ifdef
#define PI 3.14159

#ifdef PI
    #undef PI
#endif

int main(){
    // this will throw an error as PI is undefined
    cout << "Value of PI is " << PI << endl;

    return 0;
}
Ex : ifndef
#ifndef PI
    #define PI 3.14159
#endif

int main(){
    cout << "Value of PI is " << PI << endl;

    return 0;
}
Ex : if
#define NUM 10

#if NUM == 10
    #undef NUM
    #define NUM 20
#endif

int main(){
    cout << NUM << endl;

    return 0;
}
Ex : elif
#define NUM 10

#if NUM == 5
    #undef NUM
    #define NUM 10
#elif NUM == 10
    #undef NUM
    #define NUM 15
#endif

int main(){
    cout << NUM << endl;

    return 0;
}
Ex : else
#ifdef NUM
    #undef NUM
    #define NUM 10
#else
    #define NUM 15
#endif

int main(){
    cout << NUM << endl;

    return 0;
}