C++ OOP Concepts: Inheritance, Polymorphism, and Exception Handling
Inline Functions in C++
Inline functions instruct the compiler to insert the function’s code directly where it’s called, avoiding the overhead of a regular function call. This can improve execution speed, especially for small, frequently called functions.
Purpose
The primary goal of inline functions is to eliminate the overhead associated with function calls, such as saving registers, pushing arguments to the stack, and jumping to the function’s location.
Performance
Inlining enhances performance for small, frequently called functions. However, for complex functions (e.g., with loops, recursion, or large bodies), the compiler might ignore the inline request to prevent code bloat.
Syntax
In C++, the inline
keyword defines an inline function:
inline int add(int a, int b) {
return a + b;
}
Limitations and Usage
Excessive inlining can increase code size and decrease performance due to instruction cache misses. Use inline functions judiciously for small, frequently used functions where the performance benefit outweighs potential code size increases.
Finding the Largest Element in an Array (C++ Template)
#include <iostream>
using namespace std;
int main() {
int i, n;
float arr[100];
cout << "Enter total number of elements(1 to 100): ";
cin >> n;
cout << endl;
for (i = 0; i < n; ++i) {
cout << "Enter Number " << i + 1 << " : ";
cin >> arr[i];
}
for (i = 1; i < n; ++i) {
if (arr[0] < arr[i]) {
arr[0] = arr[i];
}
}
cout << endl << "Largest element = " << arr[0];
return 0;
}
Access Specifiers in C++ Inheritance
Access specifiers (private, protected, public) control how class members are accessed within the class, by derived classes, and by external code.
Private
- Visible only within the defining class.
- Not directly inherited by derived classes but can be accessed indirectly via public or protected base class methods.
- Used for encapsulation.
Protected
- Visible within the defining class and all derived classes.
- Inherited by derived classes but not publicly accessible from outside.
- Allows derived classes to access and modify base class members while restricting external access.
Public
- Visible everywhere (base class, derived classes, external code).
- Fully inherited with no restrictions.
- Provides unrestricted access.
Order of Constructor Calls in Inheritance
When a derived class object is created, constructors are called in a specific order:
- Base Class Constructor: Initializes the base class portion. If the base class inherits from other classes, their constructors are called recursively up the inheritance hierarchy.
- Derived Class Constructor: Initializes the derived class portion after the base class is fully initialized.
Abstract Base Classes in C++
An abstract base class (ABC) cannot be instantiated directly and serves as a blueprint for derived classes. It enforces a common interface.
Creating Abstract Classes
A class becomes abstract when it has at least one pure virtual function. A pure virtual function is declared with = 0
in its declaration within the base class.
Example
class Shape {
public:
virtual void display_area() = 0; // Pure virtual function
};
class Circle : public Shape {
public:
void display_area() override { /* Implementation */ }
};
Friend Functions in C++
A friend function can access private and protected members of a class, even though it’s not a class member. This is useful for operations requiring access to internal state without exposing it publicly.
Example: Multiplying Private Numbers
class XYZ;
class ABC {
private:
int value;
public:
ABC() { value = 6; }
friend int multiply(ABC, XYZ);
};
class XYZ {
private:
int value;
public:
XYZ() { value = 4; }
friend int multiply(ABC, XYZ);
};
int multiply(ABC v1, XYZ v2) {
return (v1.value * v2.value);
}
int main() {
ABC a;
XYZ x;
cout << "Product: " << multiply(a, x) << endl; // Output: 24
return 0;
}
Overloading the Unary Increment Operator (++)
#include <iostream>
using namespace std;
class Complex {
int a, b;
public:
Complex(int real = 0, int imag = 0) : a(real), b(imag) {}
void operator++() {
++a;
++b;
}
void display() {
cout << a <<" +" << b <<"" << endl;
}
};
int main() {
Complex c(1, 2);
++c; // Increment
c.display(); // Output: 2 + 3i
return 0;
}
Counting Words in a Text File (C++)
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main() {
string filename;
cout << "Enter filename: ";
cin >> filename;
ifstream file(filename);
if (!file.is_open()) {
cerr << "Error opening file." << endl;
return 1;
}
int wordCount = 0;
string word;
while (file >> word) {
wordCount++;
}
cout << "Word count: " << wordCount << endl;
return 0;
}
Exception Handling in C++
Exceptions are events that disrupt normal program flow. C++ uses try
, catch
, and throw
for exception handling.
try {
// Code that might throw an exception
if (/* some condition */) {
throw "Error message"; // Throwing an exception
}
} catch (const char* msg) {
// Handling the exception
cerr << "Error: " << msg << endl;
}
Constructors in C++
Constructors initialize objects when created. Types include:
- Default Constructor: No parameters, initializes with default values.
- Parameterized Constructor: Takes parameters for specific initialization.
- Copy Constructor: Creates a copy of an existing object.
- Move Constructor: Transfers resources from a temporary object.
Operator Overloading in C++
Operator overloading gives special meaning to operators for user-defined types, improving code readability and allowing user-defined types to behave like built-in types.
Shape, Triangle, and Rectangle Area Calculation (C++ Polymorphism)
#include <iostream>
using namespace std;
class Shape {
protected:
double x, y;
public:
void get_data(double a, double b) { x = a; y = b; }
virtual void display_area() = 0; // Pure virtual function
};
class Triangle : public Shape {
public:
void display_area() override {
cout << "Area of Triangle: " << 0.5 * x * y << endl;
}
};
class Rectangle : public Shape {
public:
void display_area() override {
cout << "Area of Rectangle: " << x * y << endl;
}
};
int main() {
Shape* shapePtr;
Triangle triangle;
Rectangle rectangle;
double x, y;
char choice;
cout << "Choose (t for Triangle, r for Rectangle): ";
cin >> choice;
cout << "Enter two dimensions: ";
cin >> x >> y;
if (choice == 't' || choice == 'T') {
shapePtr = ▵
} else if (choice == 'r' || choice == 'R') {
shapePtr = &rectangle;
} else {
cout << "Invalid choice!" << endl;
return 1;
}
shapePtr->get_data(x, y);
shapePtr->display_area();
return 0;
}