Skip to content

OOPs in C++

  • OOPs stands for Object Oriented Programming.It is a programming paradigm based on the concept of objects, everything is object in OOPs.
  • OOPs is not a language, it is a concept.Almost all languages support OOPs approach.
  • main() function exist without any class in C++.That means it supports variety of programming styles.
  • Bjarne Stroustrup introduced OOPs in C++ in 1985 OOPSLA

Class and Object

  • Class is a blueprint of an object.
  • Object is an instance of a class.
  • Every new object instance is a copy of original class.

<vector> is a class and vector<int> v is an object/instance of that class.

  • same as array, but more flexible.
  • vector allows fast random access to any element.
  • It is preferred when random-access performance is the primary need.
  • vector is a class in C++ STL
// user defined class
#include <iostream>
#include <vector>
using namespace std;
class Bread {
public:
// data members(attributes) fancy name for variables in a class
string name;
int quantity;
vector<string> ingredients; //list of ingredients
// member functions(methods) fancy name for functions in a class
void display() {
cout << "Bread name: " << name << endl;
cout << "Quantity: " << quantity << endl;
cout << "Ingredients: ";
for (string ingredient : ingredients) {
cout << ingredient << " ";
}
cout << endl;
}
}; // do not forget semicolon
// access modifier
// public: accessible from anywhere
// private: accessible only within the class
// protected: accessible within the class and derived classes
// The default access modifier for a class is private if not specified.
int main() {
Bread bread; // class name always starts with capital letter and object name always starts with small letter
bread.name = "Whole Wheat Bread";
bread.quantity = 10;
bread.ingredients = {"Flour", "Water", "Yeast", "Salt"};
bread.display();
Bread bread2;
bread2.name = "White Bread";
bread2.quantity = 5;
bread2.ingredients = {"Flour", "Water", "Yeast", "Salt"};
bread2.display();
return 0;
}

Constructor

  • Constructor is a special member function of a class that is automatically called when an object is created.
  • It is used to initialize the object.
  • It has the same name as the class and no return type.
  • It can take parameters.
  • It can be parameterized or non-parameterized.
  • If no constructor is defined, compiler will automatically generate a default constructor.
// default constructor
class Bread {
public:
Bread() {
cout << "Bread constructor called" << endl;
}
};
int main() {
Bread bread; //output: Bread constructor called
return 0;
}
// default values can be assigned in constructor
class Bread {
public:
Bread() {
name = "Unknown";
quantity = 1;
ingredients = {"Water"};
}
void display() {
cout << "Bread name: " << name << endl;
cout << "Quantity: " << quantity << endl;
cout << "Ingredients: ";
for (string ingredient : ingredients) {
cout << ingredient << " ";
}
cout << endl;
}
};
int main() {
Bread bread; //output: Bread constructor called
bread.display(); //output: Bread name: Unknown, Quantity: 1, Ingredients: Water
return 0;
}
// parameterized constructor
class Bread {
public:
Bread(string name, int quantity, vector<string> ingredients) {
this->name = name;
this->quantity = quantity;
this->ingredients = ingredients;
}
void display() {
cout << "Bread name: " << name << endl;
cout << "Quantity: " << quantity << endl;
cout << "Ingredients: ";
for (string ingredient : ingredients) {
cout << ingredient << " ";
}
cout << endl;
}
};
int main() {
Bread bread("Whole Wheat Bread", 10, {"Flour", "Water", "Yeast", "Salt"});
bread.display();
return 0;
}

Copy Constructor and Destructor

  • Copy constructor is a constructor that creates an object by copying another object.
  • It is used to initialize an object with the values of another object.
  • It takes the same type of object as a parameter.
// normal copy
class Bread {
public:
string name;
int quantity;
vector<string> ingredients;
Bread(string name, int quantity, vector<string> ingredients) {
this->name = name;
this->quantity = quantity;
this->ingredients = ingredients;
}
void display() {
cout << "Bread name: " << name << endl;
cout << "Quantity: " << quantity << endl;
cout << "Ingredients: ";
for (string ingredient : ingredients) {
cout << ingredient << " ";
}
cout << endl;
}
};
int main() {
Bread bread1("Whole Wheat Bread", 10, {"Flour", "Water", "Yeast", "Salt"});
Bread bread2 = bread1;
bread1.name = "White Bread";
bread1.display(); //output: Bread name: White Bread, Quantity: 10, Ingredients: Flour Water Yeast Salt
bread2.display(); //output: Bread name: Whole Wheat Bread, Quantity: 10, Ingredients: Flour Water Yeast Salt
return 0;
}
  • The normal copy works absolutely fine.

The problem arises when you want to deal with dynamic memory allocation with pointers.In Stack memory the allocation and deallocation is handled automatically.But in Heap memory the allocation and deallocation/deletion have to be done manually.Destructor is used to deallocate the memory ~ is used to define destructor also called as tilde operator.

class Bread {
public:
string *name;
Bread(string name) {
this->name = new string(name); // dynamic memory allocation with new keyword
}
// destructor
~Bread() {
delete name; // dynamic memory deallocation with delete keyword
cout << "Bread destructor called" << endl;
}
void display() {
cout << "Bread name: " << *name << endl;
}
};
int main() {
Bread bread("Whole Wheat Bread");
Bread bread2 = bread;
*bread.name = "White Bread";
bread.display(); //output: Bread name: White Bread
bread2.display(); //output: Bread name: White Bread
return 0;
}
// output: Bread destructor called
// output: Bread destructor called
  • When you don’t define a copy constructor, C++ automatically creates one.This is known as shallow copy.That means both objects will point to the same memory location.Changes made in one object will be reflected in another object.
  • To avoid this problem, we need to define our own copy constructor.This is known as deep copy.
class Bread {
public:
string *name;
Bread(string name) {
this->name = new string(name);
}
// copy constructor
// const is used to prevent the object from being modified
// &other is the deep copy of the object
Bread(const Bread &other) {
this->name = new string(*other.name); //`*` is used cause `name` is a string pointer
}
// destructor
~Bread() {
delete name;
cout << "Bread destructor called" << endl;
}
void display() {
cout << "Bread name: " << *name << endl;
}
};
int main() {
Bread bread("Whole Wheat Bread");
Bread bread2 = bread;
*bread.name = "White Bread";
bread.display(); //output: Bread name: White Bread
bread2.display(); //output: Bread name: Whole Wheat Bread
return 0;
}

Delegation constructor

  • Delegation constructor is a constructor that calls another constructor from the same class.

Suppose you have a class Bread and you want to initialize the object with default values and also with some specific values.You can use delegation constructor to avoid code duplication.

Means you just want a normal bread.The default constructor will only work if you does not pass any value but here you are telling just give me a normal bread. You are here passing one value the name normal bread.

#include <iostream>
#include <vector>
using namespace std;
class Bread {
public:
string name;
int quantity;
vector<string> ingredients;
// Delegation constructor
Bread(string name) : Bread(name, 1, {"Flour", "Water", "Yeast", "Salt"}) {}
// Main constructor
Bread(string name, int quantity, vector<string> ingredients) {
this->name = name;
this->quantity = quantity;
this->ingredients = ingredients;
}
void display() {
cout << "Bread name: " << name << endl;
cout << "Bread quantity: " << quantity << endl;
cout << "Bread ingredients: ";
for (string ingredient : ingredients) {
cout << ingredient << " ";
}
}
};
int main() {
Bread normalBread("Normal Bread");
normalBread.display();
return 0;
}

Getter and Setter

  • Getters and setters provide controlled access to class properties
#include <iostream>
#include <vector>
using namespace std;
class Bread {
private:
string name;
int quantity;
vector<string> ingredients;
public:
Bread(){
name = "Unknown";
quantity = 1;
ingredients = {"Flour", "Water", "Yeast", "Salt"};
}
Bread(string name, int quantity, vector<string> ingredients) {
this->name = name;
this->quantity = quantity;
this->ingredients = ingredients;
}
// getter
string getName() {
return name + " Bread";
}
// setter
void setName(string name) {
this->name = name;
}
// getter for quantity
int getQuantity() {
return quantity + 1;
}
// setter for quantity
void setQuantity(int quantity) {
if (quantity > 0) { // Validate before setting
this->quantity = quantity;
}
}
// getter for ingredients
vector<string> getIngredients() {
return ingredients;
}
// setter for ingredients
void setIngredients(vector<string> ingredients) {
this->ingredients = ingredients;
}
void display() {
cout << "Bread name: " << name << endl;
cout << "Bread quantity: " << quantity << endl;
cout << "Bread ingredients: ";
for (string ingredient : ingredients) {
cout << ingredient << " ";
}
}
};
int main() {
Bread bread; // Creates bread with default values
// Using setter to change values
bread.setName("Sourdough"); // Modifies private 'name' safely
bread.setQuantity(5); // Modifies private 'quantity' safely
bread.setIngredients({"Flour", "Starter"}); // Modifies private 'ingredients' safely
// Using getter to access values
cout << "Name: " << bread.getName() << endl; // Reads private 'name' safely
cout << "Quantity: " << bread.getQuantity() << endl;// Reads private 'quantity' safely
cout << "Ingredients: ";
for (string ingredient : bread.getIngredients()) {
cout << ingredient << " ";
}
cout << endl;
cout <<"---------------------"<< endl;
bread.display();
return 0;
}

const and reference

  • const is used to prevent the variable from being modified, only give read only access.
  • & is used to refer to the original variable.
#include <iostream>
#include <deque>
using namespace std;
int main() {
deque<int> items = {1, 2, 3};
// With copy
cout << "With copy:\n";
for(auto item : items) {
item = 10;
cout << "Inside loop: " << item << endl; // Shows 10
}
cout << "After loop: ";
for(int x : items) cout << x << " "; // Still 1,2,3
cout << endl;
// With reference
cout << "\nWith reference:\n";
for(auto& item : items) {
item = 10;
cout << "Inside loop: " << item << endl; // Shows 10
}
cout << "After loop: ";
for(int x : items) cout << x << " "; // Now 10,10,10
cout << endl;
for(const auto& item : items) {
cout << item << " ";
// item = 20; // Error: can't modify const
}
return 0;
}

Friend Keyword

  • Friend keyword is used to declare a friend function/friend class.
  • Friend function is a function that is not a member of a class but has access to the private members of a class.
  • It is declared in the class with the friend keyword.
  • It is defined outside the class.
  • It can access the private members of the class.
#include <iostream>
using namespace std;
class Bread {
private:
string name;
int quantity;
// friend keyword is used to declare a friend function
// & is used to pass the object by reference
friend bool compareQuantity(const Bread &lhs, const Bread &rhs);
// Another way to declare constructor
public:
Bread(string name, int quantity): name(name), quantity(quantity) {}
void display() const { // const keyword is used to prevent the function from modifying the object
cout << "Bread name: " << name << endl;
cout << "Bread quantity: " << quantity << endl;
}
};
// friend function is defined outside the class
bool compareQuantity(const Bread &lhs, const Bread &rhs) {
return lhs.quantity > rhs.quantity;
}
int main() {
Bread bread("Sourdough", 5);
Bread bread2("White Bread", 10);
bread.display();
bread2.display();
if (compareQuantity(bread, bread2)) {
cout << "bread quantity is greater than bread2 quantity" << endl;
} else {
cout << "bread2 quantity is greater than bread quantity" << endl;
}
return 0;
}
  • The same program can be written using getter and setter instead of friend keyword.
#include <iostream>
using namespace std;
class Bread {
private:
string name;
int quantity;
public:
Bread(string name, int quantity): name(name), quantity(quantity) {}
int getQuantity() const { return quantity; }
void display() const {
cout << "Bread name: " << name << endl;
cout << "Bread quantity: " << quantity << endl;
}
};
// Regular function using public interface
bool compareQuantity(const Bread &lhs, const Bread &rhs) {
return lhs.getQuantity() > rhs.getQuantity();
}
int main() {
Bread bread("Sourdough", 5);
Bread bread2("White Bread", 10);
bread.display();
bread2.display();
if (compareQuantity(bread, bread2)) {
cout << "bread quantity is greater than bread2 quantity" << endl;
} else {
cout << "bread2 quantity is greater than bread quantity" << endl;
}
return 0;
}
  • Suppose you have a Bakery System and you want to check the secret recipe of the bread.You do not want to expose the secret recipe to the outside world.But you want to let your staff check the secret recipe of the bread.If you use getter and setter then anyone can access the secret recipe.
#include <iostream>
#include <string>
using namespace std;
class Bread {
private:
string name;
double secretRecipe;
double price;
public:
Bread(string n, double recipe, double p):
name(n), secretRecipe(recipe), price(p) {}
// Added getters
string getName() const { return name; }
double getRecipe() const { return secretRecipe; }
double getPrice() const { return price; }
void display() {
cout << "Bread: " << name << ", Price: $" << price << endl;
}
};
class BakerySystem {
public:
void checkRecipe(const Bread& bread) {
cout << "Checking secret recipe: " << bread.getRecipe() << endl;
}
double getBulkPrice(const Bread& bread, int quantity) {
return bread.getPrice() * quantity * 0.9;
}
};
int main() {
Bread sourdough("Sourdough", 0.75, 5.99);
BakerySystem bakery;
sourdough.display();
bakery.checkRecipe(sourdough);
cout << "Bulk price: $" << bakery.getBulkPrice(sourdough, 10) << endl;
cout << "I stole the recipe: " << sourdough.getRecipe() << endl;
cout << "Internal price: " << sourdough.getPrice() << endl;
return 0;
}
  • The same program can be written using friend keyword instead of getter and setter where your staff can only access the secret recipe.
#include <iostream>
#include <string>
using namespace std;
class Bread {
private:
string name;
double secretRecipe;
double price;
public:
Bread(string n, double recipe, double p):
name(n), secretRecipe(recipe), price(p) {}
void display() {
cout << "Bread: " << name << ", Price: $" << price << endl;
}
friend class BakerySystem;
};
class BakerySystem {
public:
void checkRecipe(const Bread& bread) {
cout << "Checking secret recipe: " << bread.secretRecipe << endl;
}
double getBulkPrice(const Bread& bread, int quantity) {
return bread.price * quantity * 0.9;
}
};
int main() {
Bread sourdough("Sourdough", 0.75, 5.99);
BakerySystem bakery;
sourdough.display();
bakery.checkRecipe(sourdough);
cout << "Bulk price: $" << bakery.getBulkPrice(sourdough, 10) << endl;
return 0;
}

Virtual Function and Derived Class

  • Virtual function is a function that is declared in the base class and redefined in the derived class.
#include <iostream>
using namespace std;
class Bread {
public:
virtual void prepareIngredients() = 0; // pure virtual function
virtual void bake() = 0; // pure virtual function
virtual void pack() = 0; // pure virtual function
virtual ~Bread() = default; // virtual destructor
void makeBread() {
prepareIngredients();
bake();
pack();
}
};
// derived class
// `public` keyword is used to inherit the base class
// `override` keyword is used to override the virtual function
class SourdoughBread : public Bread {
public:
void prepareIngredients() override {
cout << "Preparing ingredients for Sourdough Bread" << endl;
}
void bake() override {
cout << "Baking Sourdough Bread" << endl;
}
void pack() override {
cout << "Packing Sourdough Bread" << endl;
}
};
class WhiteBread : public Bread {
public:
void prepareIngredients() override {
cout << "Preparing ingredients for White Bread" << endl;
}
void bake() override {
cout << "Baking White Bread" << endl;
}
void pack() override {
cout << "Packing White Bread" << endl;
}
};
int main() {
SourdoughBread sourdough;
WhiteBread whiteBread;
sourdough.makeBread();
whiteBread.makeBread();
return 0;
}
  • Pure virtual function is a virtual function that has no definition in the base class.
  • It is used to enforce the derived class to implement the function.
  • It is declared in the base class with = 0.
  • It is also known as abstract function.

Inheritance and Final Keyword

  • Inheritance is a mechanism that allows a class to inherit the properties and behaviors of another class.
#include <iostream>
using namespace std;
class Bread {
protected:
string name;
int quantity;
public:
Bread(string name, int quantity): name(name), quantity(quantity) {
cout << "Bread constructor: " << name << endl;
}
virtual ~Bread() {
cout << "Bread destructor: " << name << endl;
}
virtual void prepareIngredients() const {
cout << "Preparing ingredients for " << name << endl;
}
virtual void bake() const {
cout << "Baking " << name << endl;
}
virtual void pack() const {
cout << "Packing " << name << endl;
}
void makeBread() const {
prepareIngredients();
bake();
pack();
}
};
class SourdoughBread : public Bread {
public:
SourdoughBread(int quantity): Bread("Sourdough", quantity) {}
void prepareIngredients() const override {
cout << "Preparing ingredients for " << name << " Bread" << endl;
}
};
class WhiteBread : public Bread {
public:
WhiteBread(int quantity): Bread("White", quantity) {}
void prepareIngredients() const override final {
cout << "Preparing ingredients for " << name << " Bread" << endl;
}
};
// cannot override the `prepareIngredients` function with `final` keyword from WhiteBread class
// class WholeWheatBread : public WhiteBread {
// public:
// WholeWheatBread(int quantity): WhiteBread(quantity) {}
// void prepareIngredients() const override {
// cout << "Preparing ingredients for " << name << " Bread" << endl;
// }
// };
int main() {
SourdoughBread sourdough(10);
WhiteBread whiteBread(5);
sourdough.makeBread();
whiteBread.makeBread();
Bread *bread = new SourdoughBread(10);
Bread *bread2 = new WhiteBread(5);
bread->makeBread(); //`->` is used to access the member functions of the object in pointer
bread2->makeBread();
delete bread;
delete bread2;
return 0;
}

Standard Template Library (STL)

  • STL is a library of generic classes and functions that provide common data structures and algorithms.
  • It is a part of C++ Standard Library.
STL (Standard Template Library)
┌─────────────────────────────────────────────────────┐
│ │
│ ┌─────────────┐ ┌────────────┐ ┌──────────┐ │
│ │ Containers │ │ Algorithms │ │Iterators │ │
│ └─────────────┘ └────────────┘ └──────────┘ │
│ │ │ │ │
│ ┌────┴────┐ ┌────┴────┐ ┌────┴────┐ │
│ │Sequence │ │Sorting │ │Input │ │
│ │Vector │ │Searching│ │Output │ │
│ │List │ │Modifying│ │Forward │ │
│ │Deque │ │Counting │ │Bidirect │ │
│ └─────────┘ │Numeric │ │Random │ │
│ ┌────┴────┐ │Min/Max │ └─────────┘ │
│ │Associative│ │Binary │ │
│ │Set │ │Partition│ │
│ │Map │ │Heap │ │
│ │MultiSet │ └─────────┘ │
│ │MultiMap │ │
│ └─────────┘ │
└─────────────────────────────────────────────────────┘
  • Containers are used to store and manage collections of objects.
  • Algorithms are used to perform operations on containers.
  • Iterators are used to traverse the containers.

Containers

  • Containers are classified into Sequence, Associative, and Unordered containers.

    • Sequence containers store elements in a linear arrangement.
    • Associative containers store elements in a sorted order.
    • Unordered containers store elements in an unsorted order.
  • Sequence containers are further classified into Vector, List, Deque.

Vector

  • Vector is a dynamic array that can grow or shrink in size.
  • Elements are stored in a contiguous memory location.
  • Fast random access to elements.
vector<int> nums = {1, 2, 3};

List

  • List is a doubly linked list that can grow or shrink in size.
  • Elements are stored in a non-contiguous memory location.
  • Slow random access to elements.
list<int> nums = {1, 2, 3};

Deque

  • Deque is a dynamic array that can grow or shrink in size.
  • Elements are stored in a contiguous memory location.
  • Fast random access to elements.
deque<int> nums = {1, 2, 3};

Associative Containers

set

  • Set is a collection of unique elements.
  • Elements are stored in a sorted order.
  • Implemented using a binary search tree.
set<int> nums = {1, 2, 3};

map

  • Map is a collection of key-value pairs.
  • Keys are unique and stored in a sorted order.
  • Implemented using a hash table.
map<string, int> nameToAge = {{"Alice", 25}, {"Bob", 30}};

multiset

  • Multiset is a collection of elements with duplicate elements.
  • Elements are stored in a sorted order.
  • Implemented using a binary search tree.
multiset<int> nums = {1, 2, 2, 3};

multimap

  • Multimap is a collection of key-value pairs with duplicate keys.
  • Keys are stored in a sorted order.
  • Implemented using a hash table.
multimap<string, int> nameToAge = {{"Alice", 25}, {"Alice", 30}};

unordered_set

  • UnorderedSet is a collection of unique elements.
  • Elements are stored in an unsorted order.
  • Implemented using a hash table.
unordered_set<int> nums = {1, 2, 3};

unordered_map

  • UnorderedMap is a collection of key-value pairs.
  • Keys are stored in an unsorted order.
  • Implemented using a hash table.
unordered_map<string, int> nameToAge = {{"Alice", 25}, {"Bob", 30}};

Example

  • struct is a collection of variables of different data types under a single name
  • By default, all members in struct are public (unlike class where members are private by default)
  • Used for simple data grouping and organization
// Standard library includes for various data structures
#include <iostream> // Input/output
#include <vector> // Dynamic array
#include <string> // String handling
#include <deque> // Double-ended queue
#include <list> // Doubly linked list
#include <set> // Ordered unique elements
#include <map> // Key-value pairs
#include <unordered_set> // Hash-based unique elements
#include <unordered_map> // Hash-based key-value pairs
#include <ctime> // Time functions
using namespace std;
struct Product {
int ProductID;
string Name;
string Category;
double Price;
};
struct Customer {
string CustomerID;
string Name;
string Email;
};
struct Order {
int OrderID;
int ProductID;
int Quantity;
time_t OrderDate; // time_t is a data type that stores the number of seconds since the epoch
string CustomerID;
string Status;
double TotalPrice;
};
int main() {
vector<Product> products = {
{101, "Laptop", "Electronics", 1000.0},
{102, "Mouse", "Electronics", 10.0},
{103, "Keyboard", "Electronics", 20.0},
{104, "Tacos", "Food", 5.0},
{105, "Loaf", "Food", 5.0},
{106, "Sofa", "Furniture", 100.0},
{107, "Table", "Furniture", 50.0}
};
deque<string> customers = {"C001", "C002", "C003", "C004", "C005", "C006", "C007"};
customers.push_back("C008");
customers.push_front("C000"); // expensive operation
list<Order> orderHistory = {};
orderHistory.push_back({1, 101, 1, time(nullptr), "C001", "Pending"}); // nullptr is a macro that returns the current time
orderHistory.push_back({2, 102, 2, time(nullptr), "C002", "Pending"});
orderHistory.push_back({3, 103, 1, time(nullptr), "C003", "Pending"});
orderHistory.push_back({4, 104, 3, time(nullptr), "C004", "Processing"});
orderHistory.push_back({5, 105, 2, time(nullptr), "C005", "Processing"});
orderHistory.push_back({6, 106, 1, time(nullptr), "C006", "Processing"});
orderHistory.push_back({7, 107, 1, time(nullptr), "C007", "Processing"});
orderHistory.push_back({8, 103, 1, time(nullptr), "C001", "Processing"});
orderHistory.push_back({9, 104, 1, time(nullptr), "C001", "Processing"});
orderHistory.push_back({10, 105, 1, time(nullptr), "C001", "Processing"});
set<string> categories;
for (const auto& product : products) {
categories.insert(product.Category); // insert the category of the product into the set
}
for (const auto& category : categories) {
cout << category << endl;
}
map<int, int> productCount = {
{101, 4},
{102, 2},
{103, 7},
{104, 3},
{105, 2},
{106, 1},
{107, 1}
};
for (const auto& pair : productCount) {
cout << pair.first << " " << pair.second << endl;
}
multimap<string, Order> ordersByCustomer;
for (const auto& order : orderHistory) {
ordersByCustomer.insert({order.CustomerID, order}); // insert the order into the multimap of orders by customer
}
for (const auto& pair : ordersByCustomer) {
cout << pair.first << " " << pair.second.ProductID << endl;
}
unordered_map<string, string> customerEmail = {
{"C001", "email1@example.com"},
{"C002", "email2@example.com"},
{"C003", "email3@example.com"},
{"C004", "email4@example.com"},
{"C005", "email5@example.com"}
};
for (const auto& pair : customerEmail) {
cout << pair.first << " " << pair.second << endl;
}
unordered_set<string> uniqueCustomers;
for (const auto& order : orderHistory) {
uniqueCustomers.insert(order.CustomerID);
}
for (const auto& customer : uniqueCustomers) {
cout << customer << endl;
}
return 0;
}

Employee Management System with STL

#include <iostream>
#include <string>
using namespace std;
struct Employee {
int id;
string name;
int age;
double salary;
};
void addEmployee(Employee* employees, int index) {
employees[index].id = index + 1;
cout << "Enter name: ";
cin >> employees[index].name;
cout << "Enter age: ";
cin >> employees[index].age;
cout << "Enter salary: ";
cin >> employees[index].salary;
}
void printEmployees(const Employee* employees, int size) {
for(int i = 0; i < size; i++) {
cout << "\nEmployee " << i + 1 << ":" << endl;
cout << "ID: " << employees[i].id << endl;
cout << "Name: " << employees[i].name << endl;
cout << "Age: " << employees[i].age << endl;
cout << "Salary: " << employees[i].salary << endl;
}
}
int main() {
int size;
cout << "Enter number of employees: ";
cin >> size;
Employee* employees = new Employee[size]; // Dynamic allocation
for(int i = 0; i < size; i++) {
addEmployee(employees, i);
}
printEmployees(employees, size);
delete[] employees; // Free memory
return 0;
}

Algorithm and Iterator

#include<iostream>
#include<vector>
#include<algorithm>
#include<numeric>
#include<iterator>
#include<string>
using namespace std;
struct Employee {
int id;
string name;
int age;
double salary;
};
void printEmployee(const Employee& employee) {
cout << "ID: " << employee.id << endl;
cout << "Name: " << employee.name << endl;
cout << "Age: " << employee.age << endl;
cout << "Salary: " << employee.salary << endl;
}
int main() {
vector<Employee> employees = {
{1, "Alice", 25, 50000},
{2, "Bob", 30, 60000},
{3, "Charlie", 35, 70000},
{4, "Dave", 40, 800000},
{5, "Eve", 45, 90000},
{6, "Frank", 50, 100000},
{7, "Grace", 55, 110000},
{8, "Hank", 60, 120000},
{9, "Ivy", 65, 130000},
{10, "Jack", 70, 140000}
};
// sort the employees by salary
// lambda function is used to sort the employees by salary
sort(employees.begin(), employees.end(), [](const Employee& a, const Employee& b) {
return a.salary > b.salary;
});
cout << "Employees sorted by salary:" << endl;
for_each(employees.begin(), employees.end(), printEmployee);
// find the employees with salary greater than 80000
vector<Employee> highEarners;
copy_if(employees.begin(), employees.end(), back_inserter(highEarners), [](const Employee& e) {
return e.salary > 80000;
});
cout << "High earners:" << endl;
for_each(highEarners.begin(), highEarners.end(), printEmployee);
// calculate the total salary of all employees
// 0.0 is the initial value of the sum
double totalSalary = accumulate(employees.begin(), employees.end(), 0.0, [](double sum, const Employee& e) {
return sum + e.salary;
});
cout << "Total salary: " << totalSalary << endl;
double averageSalary = totalSalary / employees.size();
cout << "Average salary: " << averageSalary << endl;
// find the employee with the highest salary
// auto is used to deduce the type of the variable
auto highestSalaryEmployee = max_element(employees.begin(), employees.end(), [](const Employee& a, const Employee& b) {
return a.salary < b.salary;
});
cout << "Employee with the highest salary:" << endl;
printEmployee(*highestSalaryEmployee);
// find the employee with the lowest salary
auto lowestSalaryEmployee = min_element(employees.begin(), employees.end(), [](const Employee& a, const Employee& b) {
return a.salary < b.salary;
});
cout << "Employee with the lowest salary:" << endl;
printEmployee(*lowestSalaryEmployee);
return 0;
}