Practical applications of C++ programming concepts in real-world scenarios
C++ is used in countless real-world applications from operating systems to game engines. Understanding how C++ concepts apply to practical problems is key to mastering the language. Below are real-life examples for each major C++ concept.
Decision-making in real applications
Conditional statements are used in traffic control systems to manage light changes based on time, sensor input, or traffic density.
// Simplified traffic light control
#include <iostream>
using namespace std;
int main() {
int trafficDensity = 75; // Percentage of road capacity
bool emergencyVehicle = false;
if (emergencyVehicle) {
cout << "All lights GREEN for emergency vehicle" << endl;
} else if (trafficDensity > 80) {
cout << "Extend GREEN time for main road" << endl;
} else if (trafficDensity < 20) {
cout << "Switch to energy-saving mode" << endl;
} else {
cout << "Normal operation sequence" << endl;
}
return 0;
}
Conditional statements verify user credentials and determine access levels in authentication systems.
// Simple user authentication
#include <iostream>
#include <string>
using namespace std;
int main() {
string username = "admin";
string password = "secure123";
string inputUser, inputPass;
cout << "Enter username: ";
cin >> inputUser;
cout << "Enter password: ";
cin >> inputPass;
if (inputUser == username && inputPass == password) {
cout << "Access granted! Welcome admin." << endl;
} else if (inputUser == username) {
cout << "Incorrect password. Try again." << endl;
} else {
cout << "Invalid username." << endl;
}
return 0;
}
Repetitive tasks in applications
Loops are essential for continuously running systems like clocks, monitoring tools, and servers.
// Simplified digital clock using loops
#include <iostream>
#include <unistd.h> // For sleep function
using namespace std;
int main() {
int hours = 0, minutes = 0, seconds = 0;
// Simulate 24 hours of clock time
for (hours = 0; hours < 24; hours++) {
for (minutes = 0; minutes < 60; minutes++) {
for (seconds = 0; seconds < 60; seconds++) {
// Clear screen (system dependent)
cout << "\033[2J\033[1;1H"; // ANSI escape codes
cout << "Digital Clock Simulation" << endl;
cout << "Time: " << hours << ":" << minutes << ":" << seconds << endl;
sleep(1); // Wait for 1 second
}
}
}
return 0;
}
Loops process large datasets, such as analyzing sensor readings or customer records.
// Processing sensor data with loops
#include <iostream>
using namespace std;
int main() {
const int NUM_SENSORS = 10;
double sensorReadings[NUM_SENSORS] = {23.5, 24.1, 22.8, 25.3, 23.9,
24.8, 22.5, 23.7, 24.5, 23.2};
double total = 0.0, average;
// Calculate average temperature
for (int i = 0; i < NUM_SENSORS; i++) {
total += sensorReadings[i];
}
average = total / NUM_SENSORS;
cout << "Average temperature: " << average << "°C" << endl;
// Identify sensors with above-average readings
cout << "Sensors above average: ";
for (int i = 0; i < NUM_SENSORS; i++) {
if (sensorReadings[i] > average) {
cout << "Sensor " << i+1 << " (" << sensorReadings[i] << "), ";
}
}
cout << endl;
return 0;
}
Storing and processing collections of data
Arrays store and process multiple values, such as student grades in a classroom.
// Student grade management using arrays
#include <iostream>
using namespace std;
int main() {
const int NUM_STUDENTS = 5;
string students[NUM_STUDENTS] = {"Alice", "Bob", "Charlie", "Diana", "Evan"};
int grades[NUM_STUDENTS] = {85, 92, 78, 88, 95};
// Calculate class average
int total = 0;
for (int i = 0; i < NUM_STUDENTS; i++) {
total += grades[i];
}
double average = static_cast<double>(total) / NUM_STUDENTS;
// Find highest and lowest grades
int highest = grades[0], lowest = grades[0];
string topStudent = students[0], bottomStudent = students[0];
for (int i = 1; i < NUM_STUDENTS; i++) {
if (grades[i] > highest) {
highest = grades[i];
topStudent = students[i];
}
if (grades[i] < lowest) {
lowest = grades[i];
bottomStudent = students[i];
}
}
// Display results
cout << "Class Grade Report" << endl;
cout << "Average grade: " << average << endl;
cout << "Highest grade: " << highest << " by " << topStudent << endl;
cout << "Lowest grade: " << lowest << " by " << bottomStudent << endl;
return 0;
}
Arrays manage product inventories in retail systems.
// Simple inventory management system
#include <iostream>
#include <string>
using namespace std;
int main() {
const int MAX_PRODUCTS = 100;
string products[MAX_PRODUCTS];
int quantities[MAX_PRODUCTS];
int productCount = 0;
// Add some sample products
products[productCount] = "Laptop";
quantities[productCount] = 15;
productCount++;
products[productCount] = "Mouse";
quantities[productCount] = 42;
productCount++;
products[productCount] = "Keyboard";
quantities[productCount] = 25;
productCount++;
// Display inventory
cout << "Current Inventory:" << endl;
for (int i = 0; i < productCount; i++) {
cout << products[i] << ": " << quantities[i] << " units" << endl;
}
// Check for low stock items
cout << "\nLow Stock Alert:" << endl;
bool lowStockFound = false;
for (int i = 0; i < productCount; i++) {
if (quantities[i] < 20) {
cout << "LOW: " << products[i] << " (only " << quantities[i] << " left)" << endl;
lowStockFound = true;
}
}
if (!lowStockFound) {
cout << "No low stock items." << endl;
}
return 0;
}
Text processing in applications
Strings process and analyze text data, such as counting words or finding patterns.
// Simple text analysis tool
#include <iostream>
#include <string>
#include <cctype> // For character functions
using namespace std;
int main() {
string text = "C++ is a powerful programming language. "
"It is widely used for system software, game development, "
"and performance-critical applications.";
// Count words
int wordCount = 0;
bool inWord = false;
for (char c : text) {
if (isalpha(c)) {
if (!inWord) {
wordCount++;
inWord = true;
}
} else {
inWord = false;
}
}
// Count sentences
int sentenceCount = 0;
for (char c : text) {
if (c == '.' || c == '!' || c == '?') {
sentenceCount++;
}
}
// Find occurrences of "C++"
int cppCount = 0;
size_t pos = text.find("C++");
while (pos != string::npos) {
cppCount++;
pos = text.find("C++", pos + 1);
}
// Display analysis results
cout << "Text Analysis Results:" << endl;
cout << "Total characters: " << text.length() << endl;
cout << "Word count: " << wordCount << endl;
cout << "Sentence count: " << sentenceCount << endl;
cout << "Occurrences of 'C++': " << cppCount << endl;
return 0;
}
String operations validate and check password strength based on various criteria.
// Password strength checker
#include <iostream>
#include <string>
#include <cctype>
using namespace std;
bool isStrongPassword(const string& password) {
bool hasUpper = false, hasLower = false;
bool hasDigit = false, hasSpecial = false;
if (password.length() < 8) {
cout << "Password must be at least 8 characters long." << endl;
return false;
}
for (char c : password) {
if (isupper(c)) hasUpper = true;
else if (islower(c)) hasLower = true;
else if (isdigit(c)) hasDigit = true;
else hasSpecial = true;
}
if (!hasUpper) {
cout << "Password must contain at least one uppercase letter." << endl;
return false;
}
if (!hasLower) {
cout << "Password must contain at least one lowercase letter." << endl;
return false;
}
if (!hasDigit) {
cout << "Password must contain at least one digit." << endl;
return false;
}
if (!hasSpecial) {
cout << "Password must contain at least one special character." << endl;
return false;
}
return true;
}
int main() {
string password;
cout << "Enter a password to check: ";
cin >> password;
if (isStrongPassword(password)) {
cout << "Password is strong!" << endl;
} else {
cout << "Password is weak. Please try again." << endl;
}
return 0;
}
Modular programming and recursive algorithms
Functions create modular banking operations like deposits, withdrawals, and balance checks.
// Simple banking system using functions
#include <iostream>
using namespace std;
// Function declarations
void showMenu();
void deposit(double &balance);
void withdraw(double &balance);
void showBalance(double balance);
int main() {
double balance = 0.0;
int choice;
do {
showMenu();
cin >> choice;
switch (choice) {
case 1:
deposit(balance);
break;
case 2:
withdraw(balance);
break;
case 3:
showBalance(balance);
break;
case 4:
cout << "Thank you for banking with us!" << endl;
break;
default:
cout << "Invalid choice. Please try again." << endl;
}
} while (choice != 4);
return 0;
}
void showMenu() {
cout << "\n*** Banking Menu ***" << endl;
cout << "1. Deposit Money" << endl;
cout << "2. Withdraw Money" << endl;
cout << "3. Show Balance" << endl;
cout << "4. Exit" << endl;
cout << "Enter your choice: ";
}
void deposit(double &balance) {
double amount;
cout << "Enter amount to deposit: $";
cin >> amount;
if (amount > 0) {
balance += amount;
cout << "Successfully deposited $" << amount << endl;
} else {
cout << "Invalid amount. Deposit failed." << endl;
}
}
void withdraw(double &balance) {
double amount;
cout << "Enter amount to withdraw: $";
cin >> amount;
if (amount > 0 && amount <= balance) {
balance -= amount;
cout << "Successfully withdrew $" << amount << endl;
} else if (amount > balance) {
cout << "Insufficient funds. Withdrawal failed." << endl;
} else {
cout << "Invalid amount. Withdrawal failed." << endl;
}
}
void showBalance(double balance) {
cout << "Your current balance is: $" << balance << endl;
}
Recursion navigates hierarchical structures like file systems or organizational charts.
// Simulating file system navigation with recursion
#include <iostream>
#include <vector>
#include <string>
using namespace std;
// Structure to represent a file system node
struct FileSystemNode {
string name;
bool isDirectory;
vector<FileSystemNode*> children;
};
// Recursive function to display file system structure
void displayFileSystem(const FileSystemNode* node, int depth = 0) {
if (!node) return;
// Indent based on depth
for (int i = 0; i < depth; i++) {
cout << " ";
}
// Display node name with appropriate icon
if (node->isDirectory) {
cout << "[D] " << node->name << "/" << endl;
} else {
cout << "[F] " << node->name << endl;
}
// Recursively display children
for (const auto& child : node->children) {
displayFileSystem(child, depth + 1);
}
}
int main() {
// Create a sample file system structure
FileSystemNode root{"C:", true, {}};
FileSystemNode programs{"Program Files", true, {}};
FileSystemNode users{"Users", true, {}};
FileSystemNode documents{"Documents", true, {}};
FileSystemNode photos{"Photos", true, {}};
FileSystemNode app1{"App1", true, {}};
FileSystemNode app2{"App2", true, {}};
FileSystemNode exe1{"app1.exe", false, {}};
FileSystemNode exe2{"app2.exe", false, {}};
FileSystemNode readme{"readme.txt", false, {}};
FileSystemNode vacation{"vacation.jpg", false, {}};
FileSystemNode report{"report.docx", false, {}};
// Build the file system hierarchy
app1.children.push_back(&exe1);
app2.children.push_back(&exe2);
programs.children.push_back(&app1);
programs.children.push_back(&app2);
programs.children.push_back(&readme);
photos.children.push_back(&vacation);
documents.children.push_back(&report);
users.children.push_back(&documents);
users.children.push_back(&photos);
root.children.push_back(&programs);
root.children.push_back(&users);
// Display the file system structure
cout << "File System Structure:" << endl;
displayFileSystem(&root);
return 0;
}
Memory management and efficient data handling
Pointers and dynamic memory efficiently handle large data like image pixels.
// Image processing using dynamic memory allocation
#include <iostream>
#include <cstdlib> // For rand()
using namespace std;
struct Pixel {
unsigned char red;
unsigned char green;
unsigned char blue;
};
class Image {
private:
int width;
int height;
Pixel** pixels; // 2D array of pixels
public:
Image(int w, int h) : width(w), height(h) {
// Dynamically allocate memory for the image
pixels = new Pixel*[height];
for (int i = 0; i < height; i++) {
pixels[i] = new Pixel[width];
}
}
~Image() {
// Free dynamically allocated memory
for (int i = 0; i < height; i++) {
delete[] pixels[i];
}
delete[] pixels;
}
void generateRandomImage() {
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
pixels[y][x].red = rand() % 256;
pixels[y][x].green = rand() % 256;
pixels[y][x].blue = rand() % 256;
}
}
}
void convertToGrayscale() {
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
unsigned char gray = (
pixels[y][x].red * 0.3 +
pixels[y][x].green * 0.59 +
pixels[y][x].blue * 0.11
);
pixels[y][x].red = gray;
pixels[y][x].green = gray;
pixels[y][x].blue = gray;
}
}
}
void displayImageInfo() {
cout << "Image Information:" << endl;
cout << "Width: " << width << " pixels" << endl;
cout << "Height: " << height << " pixels" << endl;
cout << "Total pixels: " << width * height << endl;
cout << "Memory used: " << width * height * sizeof(Pixel) << " bytes" << endl;
}
};
int main() {
// Create a new image
Image myImage(800, 600);
myImage.displayImageInfo();
// Generate a random colorful image
myImage.generateRandomImage();
cout << "Generated random colorful image." << endl;
// Convert to grayscale
myImage.convertToGrayscale();
cout << "Converted image to grayscale." << endl;
// Image object will be automatically destroyed when it goes out of scope
// Destructor will free the dynamically allocated memory
return 0;
}
Pointers create dynamic data structures like linked lists for efficient data management.
// Linked list implementation using pointers
#include <iostream>
using namespace std;
struct Node {
int data;
Node* next;
};
class LinkedList {
private:
Node* head;
public:
LinkedList() : head(nullptr) {}
~LinkedList() {
// Free all allocated memory when the list is destroyed
Node* current = head;
while (current != nullptr) {
Node* next = current->next;
delete current;
current = next;
}
}
void append(int value) {
Node* newNode = new Node{value, nullptr};
if (head == nullptr) {
head = newNode;
} else {
Node* current = head;
while (current->next != nullptr) {
current = current->next;
}
current->next = newNode;
}
}
void prepend(int value) {
Node* newNode = new Node{value, head};
head = newNode;
}
void remove(int value) {
if (head == nullptr) return;
if (head->data == value) {
Node* toDelete = head;
head = head->next;
delete toDelete;
return;
}
Node* current = head;
while (current->next != nullptr) {
if (current->next->data == value) {
Node* toDelete = current->next;
current->next = current->next->next;
delete toDelete;
return;
}
current = current->next;
}
}
void display() {
Node* current = head;
cout << "Linked List: ";
while (current != nullptr) {
cout << current->data;
if (current->next != nullptr) {
cout << " -> ";
}
current = current->next;
}
cout << " -> NULL" << endl;
}
};
int main() {
LinkedList list;
// Add elements to the list
list.append(10);
list.append(20);
list.append(30);
list.prepend(5);
list.display(); // Output: 5 -> 10 -> 20 -> 30 -> NULL
// Remove an element
list.remove(20);
list.display(); // Output: 5 -> 10 -> 30 -> NULL
// Add more elements
list.append(40);
list.append(50);
list.display(); // Output: 5 -> 10 -> 30 -> 40 -> 50 -> NULL
// The destructor will automatically free all memory when the list goes out of scope
return 0;
}
Modeling real-world entities as objects
OOP models real-world entities like bank accounts with properties and behaviors.
// Bank account system using OOP
#include <iostream>
#include <string>
using namespace std;
class BankAccount {
private:
string accountNumber;
string accountHolder;
double balance;
static int totalAccounts; // Static member to track total accounts
public:
BankAccount(const string& number, const string& holder, double initialBalance = 0.0)
: accountNumber(number), accountHolder(holder), balance(initialBalance) {
totalAccounts++;
}
~BankAccount() {
totalAccounts--;
}
void deposit(double amount) {
if (amount > 0) {
balance += amount;
cout << "Deposited $" << amount << ". New balance: $" << balance << endl;
} else {
cout << "Invalid deposit amount." << endl;
}
}
void withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
cout << "Withdrew $" << amount << ". New balance: $" << balance << endl;
} else if (amount > balance) {
cout << "Insufficient funds. Withdrawal failed." << endl;
} else {
cout << "Invalid withdrawal amount." << endl;
}
}
void display() const {
cout << "Account Number: " << accountNumber << endl;
cout << "Account Holder: " << accountHolder << endl;
cout << "Balance: $" << balance << endl;
}
static int getTotalAccounts() {
return totalAccounts;
}
};
// Initialize static member
int BankAccount::totalAccounts = 0;
class SavingsAccount : public BankAccount {
private:
double interestRate;
public:
SavingsAccount(const string& number, const string& holder,
double initialBalance, double rate)
: BankAccount(number, holder, initialBalance), interestRate(rate) {}
void applyInterest() {
double interest = getBalance() * interestRate / 100;
deposit(interest);
cout << "Interest applied: $" << interest << endl;
}
double getBalance() const {
// In a real implementation, we would have a getter for balance
// For simplicity, we'll return a fixed value here
return 1000; // Placeholder
}
};
int main() {
// Create a regular bank account
BankAccount account("12345678", "John Doe", 500.0);
account.display();
account.deposit(250.0);
account.withdraw(100.0);
cout << endl;
// Create a savings account
SavingsAccount savings("87654321", "Jane Smith", 1000.0, 2.5);
savings.display();
savings.applyInterest();
cout << endl;
cout << "Total bank accounts: " << BankAccount::getTotalAccounts() << endl;
return 0;
}
OOP models e-commerce products with inheritance for different product types.
// E-commerce product system using OOP and inheritance
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Product {
protected:
string id;
string name;
double price;
int stock;
public:
Product(const string& productId, const string& productName,
double productPrice, int productStock)
: id(productId), name(productName), price(productPrice), stock(productStock) {}
virtual ~Product() {}
virtual void display() const {
cout << "ID: " << id << ", Name: " << name
<< ", Price: $" << price << ", Stock: " << stock;
}
virtual double calculateDiscount() const {
return 0.0; // No discount by default
}
bool purchase(int quantity) {
if (quantity <= stock) {
stock -= quantity;
return true;
}
return false;
}
string getId() const { return id; }
string getName() const { return name; }
double getPrice() const { return price; }
int getStock() const { return stock; }
};
class Book : public Product {
private:
string author;
string isbn;
public:
Book(const string& productId, const string& productName,
double productPrice, int productStock,
const string& bookAuthor, const string& bookIsbn)
: Product(productId, productName, productPrice, productStock),
author(bookAuthor), isbn(bookIsbn) {}
void display() const override {
Product::display();
cout << ", Author: " << author << ", ISBN: " << isbn;
}
double calculateDiscount() const override {
// 10% discount on books
return price * 0.1;
}
};
class Electronics : public Product {
private:
string brand;
string model;
int warrantyMonths;
public:
Electronics(const string& productId, const string& productName,
double productPrice, int productStock,
const string& deviceBrand, const string& deviceModel,
int warranty)
: Product(productId, productName, productPrice, productStock),
brand(deviceBrand), model(deviceModel), warrantyMonths(warranty) {}
void display() const override {
Product::display();
cout << ", Brand: " << brand << ", Model: " << model
<< ", Warranty: " << warrantyMonths << " months";
}
double calculateDiscount() const override {
// 15% discount on electronics
return price * 0.15;
}
};
class ShoppingCart {
private:
vector<Product*> items;
vector<int> quantities;
public:
~ShoppingCart() {
// Note: We're not deleting the products as they are owned by the inventory
// In a real system, we would have proper memory management
}
void addItem(Product* product, int quantity = 1) {
if (product->purchase(quantity)) {
items.push_back(product);
quantities.push_back(quantity);
cout << "Added " << quantity << " of " << product->getName() << " to cart." << endl;
} else {
cout << "Not enough stock for " << product->getName() << endl;
}
}
double calculateTotal() const {
double total = 0.0;
for (size_t i = 0; i < items.size(); i++) {
double discountedPrice = items[i]->getPrice() - items[i]->calculateDiscount();
total += discountedPrice * quantities[i];
}
return total;
}
void displayCart() const {
cout << "Shopping Cart Contents:" << endl;
for (size_t i = 0; i < items.size(); i++) {
cout << quantities[i] << " x " << items[i]->getName()
<< " ($" << items[i]->getPrice() - items[i]->calculateDiscount() << " each)" << endl;
}
cout << "Total: $" << calculateTotal() << endl;
}
};
int main() {
// Create some products
Book book("B001", "C++ Programming Guide", 45.99, 10, "John Doe", "978-0123456789");
Electronics laptop("E001", "Gaming Laptop", 1299.99, 5, "TechBrand", "XPS-15", 24);
// Display product information
cout << "Product Information:" << endl;
book.display();
cout << endl;
laptop.display();
cout << endl << endl;
// Create a shopping cart and add items
ShoppingCart cart;
cart.addItem(&book, 2);
cart.addItem(&laptop, 1);
cout << endl;
cart.displayCart();
return 0;
}
Using built-in data structures and algorithms
STL containers manage collections of data like employee records.
// Employee management system using STL
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <map>
using namespace std;
struct Employee {
int id;
string name;
string department;
double salary;
Employee(int empId, const string& empName,
const string& empDept, double empSalary)
: id(empId), name(empName), department(empDept), salary(empSalary) {}
void display() const {
cout << "ID: " << id << ", Name: " << name
<< ", Department: " << department
<< ", Salary: $" << salary << endl;
}
};
class EmployeeManager {
private:
vector<Employee> employees;
map<string, int> departmentCount;
public:
void addEmployee(const Employee& emp) {
employees.push_back(emp);
departmentCount[emp.department]++;
}
void displayAllEmployees() const {
cout << "All Employees:" << endl;
for (const auto& emp : employees) {
emp.display();
}
}
void sortEmployeesByName() {
sort(employees.begin(), employees.end(),
[](const Employee& a, const Employee& b) {
return a.name < b.name;
});
}
void sortEmployeesBySalary() {
sort(employees.begin(), employees.end(),
[](const Employee& a, const Employee& b) {
return a.salary > b.salary; // Descending order
});
}
vector<Employee> findEmployeesByDepartment(const string& department) const {
vector<Employee> result;
copy_if(employees.begin(), employees.end(), back_inserter(result),
[&department](const Employee& emp) {
return emp.department == department;
});
return result;
}
void displayDepartmentStats() const {
cout << "Department Statistics:" << endl;
for (const auto& pair : departmentCount) {
cout << pair.first << ": " << pair.second << " employees" << endl;
}
}
double calculateTotalSalary() const {
double total = 0.0;
for (const auto& emp : employees) {
total += emp.salary;
}
return total;
}
double calculateAverageSalary() const {
if (employees.empty()) return 0.0;
return calculateTotalSalary() / employees.size();
}
};
int main() {
EmployeeManager manager;
// Add employees
manager.addEmployee(Employee(101, "Alice Johnson", "Engineering", 75000));
manager.addEmployee(Employee(102, "Bob Smith", "Marketing", 65000));
manager.addEmployee(Employee(103, "Charlie Brown", "Engineering", 82000));
manager.addEmployee(Employee(104, "Diana Prince", "HR", 60000));
manager.addEmployee(Employee(105, "Evan Wright", "Marketing", 58000));
// Display all employees
manager.displayAllEmployees();
cout << endl;
// Display department statistics
manager.displayDepartmentStats();
cout << endl;
// Display salary information
cout << "Total salary expenditure: $" << manager.calculateTotalSalary() << endl;
cout << "Average salary: $" << manager.calculateAverageSalary() << endl;
cout << endl;
// Find and display engineering employees
vector<Employee> engineering = manager.findEmployeesByDepartment("Engineering");
cout << "Engineering Department Employees:" << endl;
for (const auto& emp : engineering) {
emp.display();
}
cout << endl;
// Sort by salary and display
manager.sortEmployeesBySalary();
cout << "Employees sorted by salary (highest first):" << endl;
manager.displayAllEmployees();
return 0;
}
STL containers and algorithms manage and prioritize tasks.
// Task scheduler using STL priority queue
#include <iostream>
#include <queue>
#include <string>
#include <vector>
#include <ctime>
using namespace std;
enum class Priority { LOW, MEDIUM, HIGH };
struct Task {
int id;
string description;
Priority priority;
time_t addedTime;
Task(int taskId, const string& desc, Priority prio)
: id(taskId), description(desc), priority(prio) {
addedTime = time(nullptr);
}
bool operator<(const Task& other) const {
// Higher priority tasks come first
if (priority != other.priority) {
return priority < other.priority;
}
// If same priority, earlier tasks come first
return addedTime > other.addedTime;
}
void display() const {
string prioStr;
switch (priority) {
case Priority::LOW: prioStr = "LOW"; break;
case Priority::MEDIUM: prioStr = "MEDIUM"; break;
case Priority::HIGH: prioStr = "HIGH"; break;
}
cout << "Task #" << id << ": " << description
<< " [Priority: " << prioStr << "]" << endl;
}
};
class TaskScheduler {
private:
priority_queue<Task> tasks;
int nextId;
public:
TaskScheduler() : nextId(1) {}
void addTask(const string& description, Priority priority) {
tasks.push(Task(nextId++, description, priority));
cout << "Added task: " << description << endl;
}
void processNextTask() {
if (tasks.empty()) {
cout << "No tasks to process." << endl;
return;
}
Task nextTask = tasks.top();
tasks.pop();
cout << "Processing: ";
nextTask.display();
}
void displayPendingTasks() const {
// Create a copy of the priority queue to display without modifying
priority_queue<Task> temp = tasks;
if (temp.empty()) {
cout << "No pending tasks." << endl;
return;
}
cout << "Pending Tasks (in priority order):" << endl;
while (!temp.empty()) {
temp.top().display();
temp.pop();
}
}
int getPendingTaskCount() const {
return tasks.size();
}
};
int main() {
TaskScheduler scheduler;
// Add some tasks with different priorities
scheduler.addTask("Fix critical security bug", Priority::HIGH);
scheduler.addTask("Prepare monthly report", Priority::MEDIUM);
scheduler.addTask("Update documentation", Priority::LOW);
scheduler.addTask("Respond to customer emergency", Priority::HIGH);
scheduler.addTask("Team lunch planning", Priority::LOW);
cout << endl;
scheduler.displayPendingTasks();
cout << endl << "Processing tasks..." << endl;
while (scheduler.getPendingTaskCount() > 0) {
scheduler.processNextTask();
}
return 0;
}
Reading from and writing to files
File handling persists student data between program executions.
// Student records system with file handling
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
using namespace std;
struct Student {
int id;
string name;
double gpa;
Student(int studentId, const string& studentName, double studentGpa)
: id(studentId), name(studentName), gpa(studentGpa) {}
void display() const {
cout << "ID: " << id << ", Name: " << name << ", GPA: " << gpa << endl;
}
};
class StudentManager {
private:
vector<Student> students;
string filename;
public:
StudentManager(const string& file) : filename(file) {
loadFromFile();
}
~StudentManager() {
saveToFile();
}
void addStudent(const Student& student) {
students.push_back(student);
}
void displayAllStudents() const {
if (students.empty()) {
cout << "No students in records." << endl;
return;
}
cout << "Student Records:" << endl;
for (const auto& student : students) {
student.display();
}
}
void loadFromFile() {
ifstream file(filename);
if (!file.is_open()) {
cout << "Could not open file for reading. Starting with empty records." << endl;
return;
}
students.clear();
int id;
string name;
double gpa;
while (file >> id) {
file.ignore(); // Ignore the space after ID
getline(file, name);
file >> gpa;
students.emplace_back(id, name, gpa);
}
file.close();
cout << "Loaded " << students.size() << " student records from file." << endl;
}
void saveToFile() const {
ofstream file(filename);
if (!file.is_open()) {
cerr << "Error: Could not open file for writing." << endl;
return;
}
for (const auto& student : students) {
file << student.id << " " << student.name << "\n" << student.gpa << "\n";
}
file.close();
cout << "Saved " << students.size() << " student records to file." << endl;
}
vector<Student> findStudentsByGPA(double minGPA) const {
vector<Student> result;
for (const auto& student : students) {
if (student.gpa >= minGPA) {
result.push_back(student);
}
}
return result;
}
};
int main() {
StudentManager manager("students.txt");
// Add some students
manager.addStudent(Student(1001, "Alice Johnson", 3.8));
manager.addStudent(Student(1002, "Bob Smith", 3.2));
manager.addStudent(Student(1003, "Charlie Brown", 3.9));
manager.addStudent(Student(1004, "Diana Prince", 3.5));
// Display all students
manager.displayAllStudents();
cout << endl;
// Find students with GPA >= 3.5
vector<Student> highAchievers = manager.findStudentsByGPA(3.5);
cout << "High Achievers (GPA >= 3.5):" << endl;
for (const auto& student : highAchievers) {
student.display();
}
// The destructor will automatically save to file
return 0;
}
File handling reads and writes configuration settings for applications.
// Configuration file parser using file handling
#include <iostream>
#include <fstream>
#include <string>
#include <map>
using namespace std;
class ConfigParser {
private:
map<string, string> settings;
string filename;
void trim(string& str) {
// Remove leading and trailing whitespace
size_t start = str.find_first_not_of(" \t\n\r\f\v");
size_t end = str.find_last_not_of(" \t\n\r\f\v");
if (start == string::npos) {
str = "";
} else {
str = str.substr(start, end - start + 1);
}
}
public:
ConfigParser(const string& file) : filename(file) {
loadConfig();
}
void loadConfig() {
ifstream file(filename);
if (!file.is_open()) {
cerr << "Warning: Could not open config file: " << filename << endl;
return;
}
string line;
while (getline(file, line)) {
// Skip empty lines and comments
if (line.empty() || line[0] == '#') {
continue;
}
// Find the equals sign
size_t equalsPos = line.find('=');
if (equalsPos == string::npos) {
continue; // Invalid line
}
// Extract key and value
string key = line.substr(0, equalsPos);
string value = line.substr(equalsPos + 1);
// Trim whitespace
trim(key);
trim(value);
// Store in map
settings[key] = value;
}
file.close();
cout << "Loaded " << settings.size() << " configuration settings." << endl;
}
void saveConfig() const {
ofstream file(filename);
if (!file.is_open()) {
cerr << "Error: Could not open config file for writing: " << filename << endl;
return;
}
file << "# Application Configuration File" << endl;
file << "# This file is auto-generated" << endl << endl;
for (const auto& pair : settings) {
file << pair.first << " = " << pair.second << endl;
}
file.close();
cout << "Saved configuration to file." << endl;
}
string getString(const string& key, const string& defaultValue = "") {
auto it = settings.find(key);
if (it != settings.end()) {
return it->second;
}
return defaultValue;
}
int getInt(const string& key, int defaultValue = 0) {
string value = getString(key);
if (value.empty()) {
return defaultValue;
}
return stoi(value);
}
double getDouble(const string& key, double defaultValue = 0.0) {
string value = getString(key);
if (value.empty()) {
return defaultValue;
}
return stod(value);
}
bool getBool(const string& key, bool defaultValue = false) {
string value = getString(key);
if (value.empty()) {
return defaultValue;
}
return (value == "true" || value == "1" || value == "yes");
}
void setString(const string& key, const string& value) {
settings[key] = value;
}
void setInt(const string& key, int value) {
settings[key] = to_string(value);
}
void setDouble(const string& key, double value) {
settings[key] = to_string(value);
}
void setBool(const string& key, bool value) {
settings[key] = value ? "true" : "false";
}
void displayAllSettings() const {
cout << "Current Configuration:" << endl;
for (const auto& pair : settings) {
cout << pair.first << " = " << pair.second << endl;
}
}
};
int main() {
ConfigParser config("app.config");
// Display current settings
config.displayAllSettings();
cout << endl;
// Get some values
string appName = config.getString("app_name", "MyApp");
int maxUsers = config.getInt("max_users", 10);
double timeout = config.getDouble("timeout", 30.0);
bool logging = config.getBool("enable_logging", true);
cout << "Application Name: " << appName << endl;
cout << "Max Users: " << maxUsers << endl;
cout << "Timeout: " << timeout << " seconds" << endl;
cout << "Logging Enabled: " << (logging ? "Yes" : "No") << endl;
cout << endl;
// Update some settings
config.setInt("max_users", 25);
config.setDouble("timeout", 45.5);
config.setBool("enable_logging", false);
// Save the updated configuration
config.saveConfig();
return 0;
}
Graceful error handling in applications
Exception handling manages errors in financial transactions.
// Bank transaction system with exception handling
#include <iostream>
#include <stdexcept>
#include <string>
using namespace std;
// Custom exception classes
class InsufficientFundsException : public exception {
private:
double balance;
double amount;
public:
InsufficientFundsException(double currentBalance, double withdrawalAmount)
: balance(currentBalance), amount(withdrawalAmount) {}
const char* what() const noexcept override {
return "Error: Insufficient funds for withdrawal";
}
double getBalance() const { return balance; }
double getAmount() const { return amount; }
};
class InvalidAmountException : public exception {
public:
const char* what() const noexcept override {
return "Error: Invalid amount specified";
}
};
class AccountNotFoundException : public exception {
private:
string accountNumber;
public:
AccountNotFoundException(const string& accNumber)
: accountNumber(accNumber) {}
const char* what() const noexcept override {
return "Error: Account not found";
}
string getAccountNumber() const { return accountNumber; }
};
class BankAccount {
private:
string accountNumber;
string accountHolder;
double balance;
public:
BankAccount(const string& accNumber, const string& holder, double initialBalance = 0.0)
: accountNumber(accNumber), accountHolder(holder), balance(initialBalance) {
if (initialBalance < 0) {
throw InvalidAmountException();
}
}
void deposit(double amount) {
if (amount <= 0) {
throw InvalidAmountException();
}
balance += amount;
cout << "Deposited $" << amount << ". New balance: $" << balance << endl;
}
void withdraw(double amount) {
if (amount <= 0) {
throw InvalidAmountException();
}
if (amount > balance) {
throw InsufficientFundsException(balance, amount);
}
balance -= amount;
cout << "Withdrew $" << amount << ". New balance: $" << balance << endl;
}
void transferTo(BankAccount& recipient, double amount) {
if (amount <= 0) {
throw InvalidAmountException();
}
if (amount > balance) {
throw InsufficientFundsException(balance, amount);
}
// Withdraw from this account
balance -= amount;
// Deposit to recipient account
recipient.balance += amount;
cout << "Transferred $" << amount << " to account " << recipient.accountNumber << endl;
cout << "Your new balance: $" << balance << endl;
}
void display() const {
cout << "Account Number: " << accountNumber << endl;
cout << "Account Holder: " << accountHolder << endl;
cout << "Balance: $" << balance << endl;
}
string getAccountNumber() const { return accountNumber; }
};
class Bank {
private:
vector<BankAccount> accounts;
public:
void addAccount(const BankAccount& account) {
accounts.push_back(account);
}
BankAccount& findAccount(const string& accountNumber) {
for (auto& account : accounts) {
if (account.getAccountNumber() == accountNumber) {
return account;
}
}
throw AccountNotFoundException(accountNumber);
}
void transfer(const string& fromAcc, const string& toAcc, double amount) {
try {
BankAccount& fromAccount = findAccount(fromAcc);
BankAccount& toAccount = findAccount(toAcc);
fromAccount.transferTo(toAccount, amount);
}
catch (const AccountNotFoundException& e) {
cerr << e.what() << endl;
throw; // Re-throw to let caller handle
}
catch (const exception& e) {
cerr << "Transfer failed: " << e.what() << endl;
throw; // Re-throw to let caller handle
}
}
};
int main() {
Bank bank;
// Create some bank accounts
try {
BankAccount account1("ACC001", "Alice Johnson", 1000.0);
BankAccount account2("ACC002", "Bob Smith", 500.0);
bank.addAccount(account1);
bank.addAccount(account2);
// Display accounts
cout << "Initial Account States:" << endl;
account1.display();
cout << endl;
account2.display();
cout << endl;
// Perform some transactions
try {
account1.deposit(250.0);
account1.withdraw(200.0);
// This will throw an exception
account2.withdraw(600.0);
}
catch (const InsufficientFundsException& e) {
cerr << e.what() << endl;
cerr << "Attempted to withdraw $" << e.getAmount()
<< " but only $" << e.getBalance() << " available." << endl;
}
catch (const exception& e) {
cerr << "Transaction error: " << e.what() << endl;
}
cout << endl;
// Try a transfer
try {
bank.transfer("ACC001", "ACC002", 300.0);
}
catch (const exception& e) {
cerr << "Transfer error: " << e.what() << endl;
}
// Try to find a non-existent account
try {
bank.findAccount("ACC999");
}
catch (const AccountNotFoundException& e) {
cerr << e.what() << ": " << e.getAccountNumber() << endl;
}
}
catch (const exception& e) {
cerr << "Account creation error: " << e.what() << endl;
return 1;
}
return 0;
}
Exception handling manages database connection errors and resource cleanup.
// Database connection manager with exception handling and RAII
#include <iostream>
#include <stdexcept>
#include <string>
using namespace std;
// Custom exception classes for database errors
class DatabaseException : public exception {
private:
string errorMessage;
public:
DatabaseException(const string& message) : errorMessage(message) {}
const char* what() const noexcept override {
return errorMessage.c_str();
}
};
class ConnectionFailedException : public DatabaseException {
public:
ConnectionFailedException(const string& message)
: DatabaseException("Connection failed: " + message) {}
};
class QueryFailedException : public DatabaseException {
public:
QueryFailedException(const string& message)
: DatabaseException("Query failed: " + message) {}
};
// Simulated database connection class
class DatabaseConnection {
private:
string connectionString;
bool isConnected;
void simulateConnectionIssue() {
// Simulate random connection issues (for demonstration)
if (rand() % 5 == 0) {
throw ConnectionFailedException("Network timeout");
}
}
void simulateQueryIssue() {
// Simulate random query issues (for demonstration)
if (rand() % 7 == 0) {
throw QueryFailedException("Syntax error");
}
}
public:
DatabaseConnection(const string& connStr)
: connectionString(connStr), isConnected(false) {}
~DatabaseConnection() {
if (isConnected) {
disconnect();
}
}
void connect() {
if (isConnected) {
return;
}
cout << "Connecting to database: " << connectionString << endl;
try {
simulateConnectionIssue();
// Simulate connection process
// In a real implementation, this would actually connect to a database
isConnected = true;
cout << "Connected successfully." << endl;
}
catch (const ConnectionFailedException& e) {
cerr << e.what() << endl;
throw; // Re-throw the exception
}
catch (const exception& e) {
cerr << "Unexpected connection error: " << e.what() << endl;
throw ConnectionFailedException(e.what());
}
}
void disconnect() {
if (!isConnected) {
return;
}
cout << "Disconnecting from database..." << endl;
isConnected = false;
cout << "Disconnected." << endl;
}
void executeQuery(const string& query) {
if (!isConnected) {
throw DatabaseException("Not connected to database");
}
cout << "Executing query: " << query << endl;
try {
simulateQueryIssue();
// Simulate query execution
cout << "Query executed successfully." << endl;
}
catch (const QueryFailedException& e) {
cerr << e.what() << endl;
throw; // Re-throw the exception
}
catch (const exception& e) {
cerr << "Unexpected query error: " << e.what() << endl;
throw QueryFailedException(e.what());
}
}
bool connected() const {
return isConnected;
}
};
class DatabaseManager {
public:
static void performDatabaseOperations() {
DatabaseConnection conn("server=localhost;database=mydb;user=admin");
try {
// Connect to database
conn.connect();
// Execute some queries
conn.executeQuery("SELECT * FROM users");
conn.executeQuery("UPDATE settings SET value = 'new' WHERE id = 1");
conn.executeQuery("INSERT INTO logs (message) VALUES ('Operation completed')");
// Disconnect (will happen automatically when conn goes out of scope)
conn.disconnect();
}
catch (const ConnectionFailedException& e) {
cerr << "Failed to establish database connection: " << e.what() << endl;
// Attempt to reconnect or implement retry logic
throw;
}
catch (const QueryFailedException& e) {
cerr << "Database query failed: " << e.what() << endl;
// Implement query retry or rollback logic
throw;
}
catch (const exception& e) {
cerr << "Unexpected database error: " << e.what() << endl;
throw;
}
}
};
int main() {
// Seed random number generator for simulation
srand(time(nullptr));
cout << "Database Operations Demo" << endl;
cout << "=======================" << endl;
try {
DatabaseManager::performDatabaseOperations();
cout << "All database operations completed successfully." << endl;
}
catch (const exception& e) {
cerr << "Database operations failed: " << e.what() << endl;
// In a real application, we might implement retry logic here
cout << "Attempting to reconnect and retry..." << endl;
// Simulate retry logic
try {
DatabaseManager::performDatabaseOperations();
cout << "Retry successful. Database operations completed." << endl;
}
catch (const exception& e) {
cerr << "Retry also failed: " << e.what() << endl;
cerr << "Please check your database connection and try again later." << endl;
return 1;
}
}
return 0;
}