Complete C++ Programming Course
Introduction to C++ Programming
C++ is a general-purpose programming language created by Bjarne Stroustrup as an extension of the C programming language. It has imperative, object-oriented and generic programming features, while also providing facilities for low-level memory manipulation.
C++ is one of the most popular programming languages and is used in systems software, application software, device drivers, embedded software, high-performance server and client applications, and entertainment software such as video games.
Key Features of C++:
- Object-Oriented Programming
- Platform Independent
- Simple and Portable
- Mid-level programming language
- Rich Library Support
- Memory Management
- Fast Performance
// Your first C++ program #include <iostream> using namespace std; int main() { cout << "Hello, World!" << endl; return 0; }
Basic Structure of a C++ Program
Every C++ program consists of one or more functions. The main() function is the entry point of every C++ program. C++ programs are typically organized with header files and source files.
Basic Components:
- Preprocessor directives (#include)
- Using directives (namespace)
- Function declarations
- Variables and data types
- Statements & Expressions
- Comments
// Basic structure of a C++ program #include <iostream> // Preprocessor directive using namespace std; // Using directive // Global variable declaration int global_var = 10; // Function declaration void custom_function(); // Main function - program entry point int main() { // Local variable declaration int local_var = 20; // Statement cout << "Global: " << global_var << ", Local: " << local_var << endl; // Function call custom_function(); return 0; // Return statement } // Function definition void custom_function() { cout << "This is a custom function." << endl; }
Object-Oriented Programming Concepts
Object-Oriented Programming (OOP) is a programming paradigm that organizes software design around data, or objects, rather than functions and logic. C++ supports several OOP concepts.
Core OOP Concepts:
| Concept | Description |
|---|---|
| Class | A blueprint for creating objects |
| Object | An instance of a class |
| Encapsulation | Binding data and functions together |
| Inheritance | Creating new classes from existing ones |
| Polymorphism | Ability to take more than one form |
| Abstraction | Hiding implementation details |
// Basic class example #include <iostream> #include <string> using namespace std; // Class definition class Car { private: string brand; string model; int year; public: // Constructor Car(string b, string m, int y) { brand = b; model = m; year = y; } // Method to display car information void displayInfo() { cout << "Brand: " << brand << endl; cout << "Model: " << model << endl; cout << "Year: " << year << endl; } // Setter method void setYear(int y) { year = y; } // Getter method int getYear() { return year; } }; int main() { // Create an object of Car Car myCar("Toyota", "Corolla", 2020); // Call method myCar.displayInfo(); // Use setter and getter myCar.setYear(2022); cout << "Updated Year: " << myCar.getYear() << endl; return 0; }
Real-world Application:
OOP concepts are used to model real-world entities and relationships. For example, in a banking system, you might have classes for Account, Customer, Transaction, etc., with methods that represent actions like deposit(), withdraw(), and transfer().
Classes and Objects in C++
A class is a user-defined data type that we can use in our program, and it works as an object constructor. An object is an instance of a class.
Class Components:
- Access specifiers (public, private, protected)
- Data members (attributes)
- Member functions (methods)
- Constructors and destructors
- Static members
- Friend functions and classes
// Classes and objects example #include <iostream> #include <string> using namespace std; class Rectangle { private: double length; double width; public: // Default constructor Rectangle() { length = 1.0; width = 1.0; } // Parameterized constructor Rectangle(double l, double w) { length = l; width = w; } // Copy constructor Rectangle(const Rectangle &other) { length = other.length; width = other.width; } // Member function to calculate area double area() { return length * width; } // Member function to calculate perimeter double perimeter() { return 2 * (length + width); } // Setter methods void setLength(double l) { if (l > 0) length = l; } void setWidth(double w) { if (w > 0) width = w; } // Getter methods double getLength() { return length; } double getWidth() { return width; } // Static member function static void displayInfo() { cout << "This is a Rectangle class" << endl; } }; int main() { // Create objects using different constructors Rectangle rect1; // Default constructor Rectangle rect2(5.0, 3.0); // Parameterized constructor Rectangle rect3 = rect2; // Copy constructor // Calculate and display area cout << "Area of rect1: " << rect1.area() << endl; cout << "Area of rect2: " << rect2.area() << endl; cout << "Area of rect3: " << rect3.area() << endl; // Use setter methods rect1.setLength(4.0); rect1.setWidth(2.5); cout << "Updated area of rect1: " << rect1.area() << endl; // Call static member function Rectangle::displayInfo(); return 0; }
Real-world Application:
Classes and objects are used to model real-world entities. For example, in a university system, you might have classes for Student, Professor, Course, etc., each with their own attributes and methods that define their behavior.
Constructors and Destructors
Constructors and destructors are special member functions of a class that are executed automatically when an object of the class is created or destroyed.
Types of Constructors:
- Default Constructor
- Parameterized Constructor
- Copy Constructor
- Move Constructor (C++11)
// Constructors and destructors example #include <iostream> #include <string> using namespace std; class Student { private: string name; int age; int *grades; int numGrades; public: // Default constructor Student() { name = "Unknown"; age = 0; grades = nullptr; numGrades = 0; cout << "Default constructor called" << endl; } // Parameterized constructor Student(string n, int a) { name = n; age = a; grades = nullptr; numGrades = 0; cout << "Parameterized constructor called" << endl; } // Copy constructor Student(const Student &other) { name = other.name; age = other.age; numGrades = other.numGrades; // Deep copy for dynamically allocated memory if (numGrades > 0) { grades = new int[numGrades]; for (int i = 0; i < numGrades; i++) { grades[i] = other.grades[i]; } } else { grades = nullptr; } cout << "Copy constructor called" << endl; } // Destructor ~Student() { delete[] grades; cout << "Destructor called for " << name << endl; } // Method to add grades void addGrade(int grade) { int *temp = new int[numGrades + 1]; // Copy existing grades for (int i = 0; i < numGrades; i++) { temp[i] = grades[i]; } // Add new grade temp[numGrades] = grade; numGrades++; // Delete old array and point to new one delete[] grades; grades = temp; } // Method to display student information void display() { cout << "Name: " << name << endl; cout << "Age: " << age << endl; cout << "Grades: "; for (int i = 0; i < numGrades; i++) { cout << grades[i] << " "; } cout << endl; } }; int main() { // Create objects using different constructors Student student1; // Default constructor Student student2("Alice", 20); // Parameterized constructor // Add grades to student2 student2.addGrade(85); student2.addGrade(90); student2.addGrade(78); // Use copy constructor Student student3 = student2; // Display student information cout << "\nStudent 2:" << endl; student2.display(); cout << "\nStudent 3 (copy of student2):" << endl; student3.display(); cout << "\nEnd of main function - destructors will be called automatically" << endl; return 0; }
Real-world Application:
Constructors are used to initialize objects with valid states, while destructors are crucial for resource management. For example, in a database application, a constructor might establish a connection to the database, while the destructor would close that connection and free up resources.
Inheritance in C++
Inheritance is a feature of Object-Oriented Programming that allows a class to inherit properties and characteristics from another class. The class that inherits is called the derived class, and the class being inherited from is called the base class.
Types of Inheritance:
- Single Inheritance
- Multiple Inheritance
- Multilevel Inheritance
- Hierarchical Inheritance
- Hybrid Inheritance
// Inheritance example #include <iostream> #include <string> using namespace std; // Base class class Vehicle { protected: string brand; string model; int year; public: Vehicle(string b, string m, int y) : brand(b), model(m), year(y) {} void displayInfo() { cout << "Brand: " << brand << endl; cout << "Model: " << model << endl; cout << "Year: " << year << endl; } }; // Derived class - Single inheritance class Car : public Vehicle { private: int doors; string fuelType; public: Car(string b, string m, int y, int d, string f) : Vehicle(b, m, y), doors(d), fuelType(f) {} void displayCarInfo() { displayInfo(); // Call base class method cout << "Doors: " << doors << endl; cout << "Fuel Type: " << fuelType << endl; } }; // Another derived class - Multilevel inheritance class SportsCar : public Car { private: int topSpeed; bool convertible; public: SportsCar(string b, string m, int y, int d, string f, int ts, bool conv) : Car(b, m, y, d, f), topSpeed(ts), convertible(conv) {} void displaySportsCarInfo() { displayCarInfo(); // Call base class method cout << "Top Speed: " << topSpeed << " mph" << endl; cout << "Convertible: " << (convertible ? "Yes" : "No") << endl; } }; // Another base class for multiple inheritance class Electric { protected: int batteryCapacity; int range; public: Electric(int bc, int r) : batteryCapacity(bc), range(r) {} void displayElectricInfo() { cout << "Battery Capacity: " << batteryCapacity << " kWh" << endl; cout << "Range: " << range << " miles" << endl; } }; // Multiple inheritance class ElectricCar : public Car, public Electric { public: ElectricCar(string b, string m, int y, int d, string f, int bc, int r) : Car(b, m, y, d, f), Electric(bc, r) {} void displayElectricCarInfo() { displayCarInfo(); displayElectricInfo(); } }; int main() { // Single inheritance example cout << "=== Car (Single Inheritance) ===" << endl; Car myCar("Toyota", "Camry", 2020, 4, "Gasoline"); myCar.displayCarInfo(); cout << "\n=== Sports Car (Multilevel Inheritance) ===" << endl; SportsCar sportsCar("Porsche", "911", 2021, 2, "Gasoline", 190, true); sportsCar.displaySportsCarInfo(); cout << "\n=== Electric Car (Multiple Inheritance) ===" << endl; ElectricCar electricCar("Tesla", "Model 3", 2022, 4, "Electric", 75, 315); electricCar.displayElectricCarInfo(); return 0; }
Real-world Application:
Inheritance is used to create hierarchical relationships between classes. For example, in a graphics application, you might have a base Shape class with derived classes like Circle, Rectangle, and Triangle, each inheriting common properties but implementing their own specific behaviors.
Polymorphism in C++
Polymorphism means "many forms". In C++, polymorphism allows us to perform a single action in different ways. There are two types of polymorphism: compile-time (function overloading, operator overloading) and runtime (virtual functions).
Types of Polymorphism:
- Compile-time Polymorphism
- Function Overloading
- Operator Overloading
- Runtime Polymorphism
- Virtual Functions
- Function Overriding
// Polymorphism example #include <iostream> #include <string> using namespace std; // Base class with virtual function class Shape { protected: string name; public: Shape(string n) : name(n) {} // Virtual function for runtime polymorphism virtual void draw() { cout << "Drawing a " << name << endl; } // Pure virtual function (makes Shape an abstract class) virtual double area() = 0; // Virtual destructor virtual ~Shape() { cout << "Shape destructor: " << name << endl; } }; // Derived class class Circle : public Shape { private: double radius; public: Circle(string n, double r) : Shape(n), radius(r) {} // Override draw function void draw() override { cout << "Drawing a circle with radius " << radius << endl; } // Implement area function double area() override { return 3.14159 * radius * radius; } }; // Another derived class class Rectangle : public Shape { private: double width; double height; public: Rectangle(string n, double w, double h) : Shape(n), width(w), height(h) {} // Override draw function void draw() override { cout << "Drawing a rectangle with width " << width << " and height " << height << endl; } // Implement area function double area() override { return width * height; } }; // Function overloading (compile-time polymorphism) void print(int i) { cout << "Printing integer: " << i << endl; } void print(double d) { cout << "Printing double: " << d << endl; } void print(const string& s) { cout << "Printing string: " << s << endl; } // Operator overloading class Vector { public: double x, y; Vector(double x = 0, double y = 0) : x(x), y(y) {} // Overload + operator Vector operator+(const Vector& other) { return Vector(x + other.x, y + other.y); } // Overload - operator Vector operator-(const Vector& other) { return Vector(x - other.x, y - other.y); } // Overload << operator for output friend ostream& operator<<(ostream& os, const Vector& v) { os << "(" << v.x << ", " << v.y << ")"; return os; } }; int main() { // Runtime polymorphism with virtual functions cout << "=== Runtime Polymorphism ===" << endl; Shape* shapes[2]; shapes[0] = new Circle("Circle", 5.0); shapes[1] = new Rectangle("Rectangle", 4.0, 6.0); for (int i = 0; i < 2; i++) { shapes[i]->draw(); // Calls the appropriate derived class function cout << "Area: " << shapes[i]->area() << endl; delete shapes[i]; } // Compile-time polymorphism: function overloading cout << "\n=== Function Overloading ===" << endl; print(10); print(3.14); print("Hello, World!"); // Compile-time polymorphism: operator overloading cout << "\n=== Operator Overloading ===" << endl; Vector v1(1.0, 2.0); Vector v2(3.0, 4.0); Vector v3 = v1 + v2; Vector v4 = v2 - v1; cout << "v1: " << v1 << endl; cout << "v2: " << v2 << endl; cout << "v1 + v2: " << v3 << endl; cout << "v2 - v1: " << v4 << endl; return 0; }
Real-world Application:
Polymorphism is used extensively in GUI frameworks, game development, and any system that needs to handle different types of objects through a common interface. For example, in a drawing application, all shapes can be drawn, moved, or resized through a common interface, even though each shape implements these operations differently.
Templates in C++
Templates are a powerful feature in C++ that allows you to write generic programs. They are the foundation of generic programming, which involves writing code in a way that is independent of any particular type.
Types of Templates:
- Function Templates
- Class Templates
- Template Specialization
- Variable Templates (C++14)
// Templates example #include <iostream> #include <string> #include <vector> using namespace std; // Function template template <typename T> T max(T a, T b) { return (a > b) ? a : b; } // Function template with multiple parameters template <typename T1, typename T2> void printPair(T1 first, T2 second) { cout << "First: " << first << ", Second: " << second << endl; } // Class template template <typename T> class Box { private: T content; public: Box(T value) : content(value) {} T getContent() { return content; } void setContent(T value) { content = value; } void display() { cout << "Box contains: " << content << endl; } }; // Template specialization for const char* template<> class Box<const char*> { private: const char* content; public: Box(const char* value) : content(value) {} const char* getContent() { return content; } void setContent(const char* value) { content = value; } void display() { cout << "Box contains string: \"" << content << "\"" << endl; } }; // Class template with non-type parameters template <typename T, int size> class Array { private: T arr[size]; public: void set(int index, T value) { if (index >= 0 && index < size) { arr[index] = value; } } T get(int index) { if (index >= 0 && index < size) { return arr[index]; } return T(); // Return default value } void display() { cout << "Array: ["; for (int i = 0; i < size; i++) { cout << arr[i]; if (i < size - 1) cout << ", "; } cout << "]" << endl; } }; int main() { // Function template examples cout << "=== Function Templates ===" << endl; cout << "max(5, 10) = " << max(5, 10) << endl; cout << "max(3.14, 2.71) = " << max(3.14, 2.71) << endl; cout << "max('a', 'z') = " << max('a', 'z') << endl; printPair(10, "Hello"); printPair(3.14, true); // Class template examples cout << "\n=== Class Templates ===" << endl; Box<int> intBox(42); intBox.display(); Box<string> stringBox("Template Example"); stringBox.display(); // Template specialization example Box<const char*> charBox("Specialized Template"); charBox.display(); // Non-type template parameter example cout << "\n=== Non-type Template Parameters ===" << endl; Array<int, 5> intArray; for (int i = 0; i < 5; i++) { intArray.set(i, i * 10); } intArray.display(); Array<string, 3> stringArray; stringArray.set(0, "Hello"); stringArray.set(1, "World"); stringArray.set(2, "!"); stringArray.display(); return 0; }
Real-world Application:
Templates are used extensively in the Standard Template Library (STL) to create generic containers and algorithms. They're also used in mathematical libraries for operations on different numeric types, and in any code that needs to work with multiple data types without duplication.
Standard Template Library (STL)
The Standard Template Library (STL) is a powerful set of C++ template classes to provide general-purpose classes and functions with templates that implement many popular and commonly used algorithms and data structures.
Main Components of STL:
- Containers - store data (vector, list, map, set, etc.)
- Algorithms - perform operations on data (sort, search, etc.)
- Iterators - access elements in containers
- Function Objects (Functors)
// STL example #include <iostream> #include <vector> #include <list> #include <map> #include <set> #include <algorithm> #include <string> using namespace std; int main() { // Vector example cout << "=== Vector ===" << endl; vector<int> numbers = {5, 2, 8, 1, 9}; cout << "Original vector: "; for (int num : numbers) { cout << num << " "; } cout << endl; // Sort the vector sort(numbers.begin(), numbers.end()); cout << "Sorted vector: "; for (int num : numbers) { cout << num << " "; } cout << endl; // List example cout << "\n=== List ===" << endl; list<string> names = {"Alice", "Bob", "Charlie"}; // Add elements to list names.push_front("Zoe"); names.push_back("David"); cout << "List contents: "; for (const string& name : names) { cout << name << " "; } cout << endl; // Map example cout << "\n=== Map ===" << endl; map<string, int> ageMap; // Insert key-value pairs ageMap["Alice"] = 25; ageMap["Bob"] = 30; ageMap["Charlie"] = 35; cout << "Map contents:" << endl; for (const auto& pair : ageMap) { cout << pair.first << ": " << pair.second << endl; } // Set example cout << "\n=== Set ===" << endl; set<int> uniqueNumbers = {5, 2, 8, 2, 5, 9, 1}; cout << "Set contents (unique, sorted): "; for (int num : uniqueNumbers) { cout << num << " "; } cout << endl; // Algorithm examples cout << "\n=== Algorithms ===" << endl; vector<int> values = {5, 2, 8, 1, 9, 3, 6, 4, 7}; // Find an element auto it = find(values.begin(), values.end(), 6); if (it != values.end()) { cout << "Found 6 at position: " << distance(values.begin(), it) << endl; } // Count elements greater than 5 int count = count_if(values.begin(), values.end(), [](int x) { return x > 5; }); cout << "Count of numbers greater than 5: " << count << endl; // Transform elements (square each element) vector<int> squaredValues; squaredValues.resize(values.size()); transform(values.begin(), values.end(), squaredValues.begin(), [](int x) { return x * x; }); cout << "Squared values: "; for (int num : squaredValues) { cout << num << " "; } cout << endl; return 0; }
Real-world Application:
The STL is used in virtually all C++ programs for efficient data storage and manipulation. For example, vectors are used for dynamic arrays, maps for key-value storage (like dictionaries), and algorithms for sorting and searching operations. Game developers use STL containers to manage game objects, and financial applications use them for data analysis.
Exception Handling in C++
Exception handling in C++ is a process to handle runtime errors. It allows us to maintain the normal flow of the application even after runtime errors.
Exception Handling Keywords:
- try - represents a block of code that can throw an exception
- catch - represents a block of code that handles the exception
- throw - used to throw an exception
// Exception handling example #include <iostream> #include <stdexcept> #include <string> using namespace std; // Custom exception class class MyException : public exception { private: string message; public: MyException(const string& msg) : message(msg) {} const char* what() const noexcept override { return message.c_str(); } }; // Function that might throw an exception double divide(double numerator, double denominator) { if (denominator == 0) { throw runtime_error("Division by zero!"); } return numerator / denominator; } // Function that throws a custom exception void processValue(int value) { if (value < 0) { throw MyException("Negative value not allowed!"); } if (value > 100) { throw out_of_range("Value is out of range!"); } cout << "Processing value: " << value << endl; } int main() { // Basic exception handling cout << "=== Basic Exception Handling ===" << endl; try { double result = divide(10, 2); cout << "10 / 2 = " << result << endl; result = divide(5, 0); // This will throw an exception cout << "5 / 0 = " << result << endl; } catch (const exception& e) { cerr << "Exception caught: " << e.what() << endl; } // Multiple catch blocks cout << "\n=== Multiple Catch Blocks ===" << endl; try { processValue(50); processValue(-5); // This will throw a custom exception processValue(150); // This will throw an out_of_range exception } catch (const MyException& e) { cerr << "Custom exception caught: " << e.what() << endl; } catch (const out_of_range& e) { cerr << "Out of range exception caught: " << e.what() << endl; } catch (const exception& e) { cerr << "Standard exception caught: " << e.what() << endl; } catch (...) { cerr << "Unknown exception caught" << endl; } // Exception safety and RAII (Resource Acquisition Is Initialization) cout << "\n=== RAII and Exception Safety ===" << endl; class FileHandler { private: string filename; public: FileHandler(const string& name) : filename(name) { cout << "Opening file: " << filename << endl; // Simulate something that might fail if (filename == "invalid.txt") { throw runtime_error("Failed to open file!"); } } ~FileHandler() { cout << "Closing file: " << filename << endl; } void process() { cout << "Processing file: " << filename << endl; } }; try { FileHandler file1("data.txt"); file1.process(); FileHandler file2("invalid.txt"); // This will throw an exception file2.process(); } catch (const exception& e) { cerr << "File error: " << e.what() << endl; } // Nested try-catch blocks cout << "\n=== Nested Try-Catch Blocks ===" << endl; try { try { processValue(-10); } catch (const MyException& e) { cerr << "Inner catch: " << e.what() << endl; // Re-throw the exception throw; } } catch (const MyException& e) { cerr << "Outer catch: " << e.what() << endl; } cout << "\nProgram continues after exception handling." << endl; return 0; }
Real-world Application:
Exception handling is crucial for building robust applications. It's used in database systems to handle connection failures, in file systems to handle missing files or permission issues, in network applications to handle connectivity problems, and in any application where runtime errors need to be handled gracefully without crashing the program.
File Handling in C++
C++ provides the fstream library for handling files. This library provides three classes: ofstream (output file stream), ifstream (input file stream), and fstream (file stream for both input and output).
File Operations:
- Opening a file
- Reading from a file
- Writing to a file
- Closing a file
- File positioning
// File handling example #include <iostream> #include <fstream> #include <string> #include <vector> using namespace std; // Function to write data to a file void writeToFile(const string& filename, const vector<string>& lines) { ofstream outFile; // Open file for writing (truncate if exists) outFile.open(filename); if (!outFile) { cerr << "Error opening file for writing: " << filename << endl; return; } // Write lines to file for (const string& line : lines) { outFile << line << endl; } outFile.close(); cout << "Data written to file successfully." << endl; } // Function to read data from a file void readFromFile(const string& filename) { ifstream inFile; // Open file for reading inFile.open(filename); if (!inFile) { cerr << "Error opening file for reading: " << filename << endl; return; } string line; cout << "File contents:" << endl; // Read file line by line while (getline(inFile, line)) { cout << line << endl; } inFile.close(); } // Function to append data to a file void appendToFile(const string& filename, const vector<string>& lines) { ofstream outFile; // Open file for appending outFile.open(filename, ios::app); if (!outFile) { cerr << "Error opening file for appending: " << filename << endl; return; } // Append lines to file for (const string& line : lines) { outFile << line << endl; } outFile.close(); cout << "Data appended to file successfully." << endl; } // Function to demonstrate binary file operations void binaryFileOperations() { // Write binary data ofstream outFile("data.bin", ios::binary); if (!outFile) { cerr << "Error opening binary file for writing." << endl; return; } int numbers[] = {10, 20, 30, 40, 50}; outFile.write(reinterpret_cast<char*>(numbers), sizeof(numbers)); outFile.close(); // Read binary data ifstream inFile("data.bin", ios::binary); if (!inFile) { cerr << "Error opening binary file for reading." << endl; return; } int readNumbers[5]; inFile.read(reinterpret_cast<char*>(readNumbers), sizeof(readNumbers)); inFile.close(); cout << "Binary data read: "; for (int num : readNumbers) { cout << num << " "; } cout << endl; } // Function to demonstrate file positioning void filePositioning() { fstream file("position.txt", ios::in | ios::out | ios::trunc); if (!file) { cerr << "Error opening file for positioning." << endl; return; } // Write some data file << "1234567890" << endl; file << "ABCDEFGHIJ" << endl; file << "KLMNOPQRST" << endl; // Go to beginning of file file.seekg(0, ios::beg); // Read first line string line; getline(file, line); cout << "First line: " << line << endl; // Move to position 5 in the file file.seekg(5, ios::beg); char ch; file.get(ch); cout << "Character at position 5: " << ch << endl; // Move to end of file file.seekg(0, ios::end); streampos endPos = file.tellg(); cout << "File size: " << endPos << " bytes" << endl; file.close(); } int main() { string filename = "example.txt"; // Write to file vector<string> lines = { "Hello, File Handling in C++!", "This is the second line.", "And this is the third line." }; writeToFile(filename, lines); // Read from file readFromFile(filename); // Append to file vector<string> newLines = { "This line was appended.", "Another appended line." }; appendToFile(filename, newLines); // Read again to show appended content readFromFile(filename); // Binary file operations cout << "\n=== Binary File Operations ===" << endl; binaryFileOperations(); // File positioning cout << "\n=== File Positioning ===" << endl; filePositioning(); // Error handling with files cout << "\n=== Error Handling ===" << endl; ifstream nonExistentFile("nonexistent.txt"); if (!nonExistentFile) { cerr << "Error: Could not open nonexistent.txt" << endl; } // Check file state flags ifstream testFile("example.txt"); if (testFile.good()) { cout << "File is in good state" << endl; } if (testFile.is_open()) { cout << "File is open" << endl; testFile.close(); } return 0; }
Real-world Application:
File handling is essential for applications that need to persist data, such as:
- Database systems for storing records
- Text editors for saving and loading documents
- Configuration files for storing application settings
- Game development for saving game progress
- Data logging applications for recording sensor data
Advanced C++ Topics
C++ offers several advanced features that provide more control and efficiency for complex programming tasks.
Advanced Topics:
- Smart Pointers
- Lambda Expressions
- Move Semantics
- Multithreading
- Type Inference (auto and decltype)
- Range-based for loops
// Advanced topics example #include <iostream> #include <memory> #include <thread> #include <vector> #include <algorithm> #include <functional> using namespace std; // Smart pointers example void smartPointers() { cout << "=== Smart Pointers ===" << endl; // Unique pointer (unique ownership) unique_ptr<int> uniquePtr = make_unique<int>(42); cout << "Unique pointer value: " << *uniquePtr << endl; // Shared pointer (shared ownership) shared_ptr<int> sharedPtr1 = make_shared<int>(100); shared_ptr<int> sharedPtr2 = sharedPtr1; cout << "Shared pointer 1 value: " << *sharedPtr1 << endl; cout << "Shared pointer 2 value: " << *sharedPtr2 << endl; cout << "Use count: " << sharedPtr1.use_count() << endl; // Weak pointer (no ownership, avoids circular references) weak_ptr<int> weakPtr = sharedPtr1; cout << "Weak pointer use count: " << weakPtr.use_count() << endl; if (!weakPtr.expired()) { shared_ptr<int> sharedPtr3 = weakPtr.lock(); cout << "Value from weak pointer: " << *sharedPtr3 << endl; } } // Lambda expressions example void lambdaExpressions() { cout << "\n=== Lambda Expressions ===" << endl; // Simple lambda auto greet = []() { cout << "Hello, Lambda!" << endl; }; greet(); // Lambda with parameters auto add = [](int a, int b) { return a + b; }; cout << "5 + 3 = " << add(5, 3) << endl; // Lambda with capture clause int multiplier = 3; auto times = [multiplier](int x) { return x * multiplier; }; cout << "5 * 3 = " << times(5) << endl; // Using lambda with STL algorithms vector<int> numbers = {5, 2, 8, 1, 9, 3, 6, 4, 7}; cout << "Numbers greater than 5: "; for_each(numbers.begin(), numbers.end(), [](int n) { if (n > 5) { cout << n << " "; } }); cout << endl; // Count even numbers int evenCount = count_if(numbers.begin(), numbers.end(), [](int n) { return n % 2 == 0; }); cout << "Count of even numbers: " << evenCount << endl; } // Move semantics example void moveSemantics() { cout << "\n=== Move Semantics ===" << endl; // Create a vector with some data vector<string> source = {"Hello", "World", "Move", "Semantics"}; cout << "Source size: " << source.size() << endl; // Move the data to a new vector vector<string> destination = move(source); cout << "After move:" << endl; cout << "Source size: " << source.size() << endl; cout << "Destination size: " << destination.size() << endl; cout << "Destination contents: "; for (const string& s : destination) { cout << s << " "; } cout << endl; } // Multithreading example void multithreading() { cout << "\n=== Multithreading ===" << endl; // Function to be executed in a thread auto threadFunction = [](int id, int count) { for (int i = 0; i < count; i++) { cout << "Thread " << id << ": " << i << endl; this_thread::sleep_for(chrono::milliseconds(100)); } }; // Create threads thread t1(threadFunction, 1, 5); thread t2(threadFunction, 2, 5); // Wait for threads to finish t1.join(); t2.join(); cout << "Threads finished execution." << endl; } // Type inference and range-based for loops void modernCppFeatures() { cout << "\n=== Modern C++ Features ===" << endl; // Type inference with auto auto number = 42; // int auto name = "John"; // const char* auto price = 19.99; // double cout << "Number: " << number << endl; cout << "Name: " << name << endl; cout << "Price: " << price << endl; // Range-based for loop vector<int> numbers = {1, 2, 3, 4, 5}; cout << "Numbers: "; for (auto n : numbers) { cout << n << " "; } cout << endl; // With reference to modify values cout << "Squared numbers: "; for (auto& n : numbers) { n = n * n; cout << n << " "; } cout << endl; // decltype for type deduction decltype(numbers) anotherVector = {10, 20, 30}; cout << "Another vector: "; for (auto n : anotherVector) { cout << n << " "; } cout << endl; } int main() { smartPointers(); lambdaExpressions(); moveSemantics(); multithreading(); modernCppFeatures(); return 0; }
Real-world Application:
Advanced C++ features are used in:
- High-performance applications (move semantics, smart pointers)
- Concurrent programming (multithreading)
- Functional programming patterns (lambda expressions)
- Generic programming (type inference)
- Modern codebases that require memory safety and performance