cpp
examples
examples.cpp⚙️cpp
/**
* Encapsulation in C++ - Comprehensive Examples
*
* Demonstrates:
* - Access modifiers
* - Getters and setters
* - Data validation
* - Friend functions and classes
*
* Compile: g++ -std=c++17 -Wall -Wextra examples.cpp -o examples
* Run: ./examples
*/
#include <iostream>
#include <string>
#include <vector>
#include <stdexcept>
#include <cmath>
using namespace std;
// ============================================================
// SECTION 1: BASIC ENCAPSULATION
// ============================================================
// Without encapsulation (vulnerable)
struct UnsafeBankAccount {
double balance; // Anyone can modify!
};
// With encapsulation (protected)
class SafeBankAccount {
private:
double balance;
string accountNumber;
public:
SafeBankAccount(const string& accNum, double initial = 0.0)
: balance(initial >= 0 ? initial : 0), accountNumber(accNum) {}
// Controlled access
double getBalance() const { return balance; }
string getAccountNumber() const { return accountNumber; }
// Validated operations
bool deposit(double amount) {
if (amount > 0) {
balance += amount;
return true;
}
return false;
}
bool withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
return true;
}
return false;
}
};
void demonstrateBasicEncapsulation() {
cout << "--- Basic Encapsulation ---\n" << endl;
// Unsafe version
UnsafeBankAccount unsafe;
unsafe.balance = 1000;
unsafe.balance = -5000; // No protection!
cout << "Unsafe account balance: $" << unsafe.balance << " (invalid!)" << endl;
// Safe version
SafeBankAccount safe("ACC001", 1000);
cout << "\nSafe account: " << safe.getAccountNumber() << endl;
cout << "Initial balance: $" << safe.getBalance() << endl;
safe.deposit(500);
cout << "After deposit $500: $" << safe.getBalance() << endl;
if (!safe.withdraw(2000)) {
cout << "Cannot withdraw $2000 - insufficient funds" << endl;
}
safe.withdraw(300);
cout << "After withdraw $300: $" << safe.getBalance() << endl;
// Cannot directly modify:
// safe.balance = -5000; // ERROR! private member
}
// ============================================================
// SECTION 2: ACCESS MODIFIERS IN ACTION
// ============================================================
class Vehicle {
public:
string brand; // Accessible everywhere
protected:
int year; // Accessible in Vehicle and derived classes
private:
string vin; // Only accessible in Vehicle
public:
Vehicle(const string& b, int y, const string& v)
: brand(b), year(y), vin(v) {}
// Public method to access private member
string getVIN() const { return vin; }
void displayInfo() const {
cout << "Brand: " << brand << endl;
cout << "Year: " << year << endl;
cout << "VIN: " << vin << endl;
}
};
class Car : public Vehicle {
public:
Car(const string& b, int y, const string& v) : Vehicle(b, y, v) {}
void showDetails() const {
cout << "Brand: " << brand << endl; // OK: public
cout << "Year: " << year << endl; // OK: protected
// cout << "VIN: " << vin << endl; // ERROR: private
cout << "VIN: " << getVIN() << endl; // OK: through public method
}
};
void demonstrateAccessModifiers() {
cout << "\n--- Access Modifiers ---\n" << endl;
Vehicle v("Toyota", 2023, "ABC123XYZ");
cout << "Accessing from outside:" << endl;
cout << " Brand (public): " << v.brand << endl;
// cout << v.year; // ERROR: protected
// cout << v.vin; // ERROR: private
cout << " VIN (via getter): " << v.getVIN() << endl;
cout << "\nCar (derived class) accessing parent:" << endl;
Car c("Honda", 2022, "DEF456UVW");
c.showDetails();
}
// ============================================================
// SECTION 3: GETTERS AND SETTERS
// ============================================================
class Person {
private:
string firstName;
string lastName;
int age;
public:
Person(const string& fn, const string& ln, int a)
: firstName(fn), lastName(ln) {
setAge(a); // Use setter for validation
}
// Simple getters
string getFirstName() const { return firstName; }
string getLastName() const { return lastName; }
int getAge() const { return age; }
// Computed property (getter only)
string getFullName() const {
return firstName + " " + lastName;
}
// Setter with validation
void setAge(int a) {
if (a >= 0 && a <= 150) {
age = a;
} else {
cout << " Invalid age: " << a << " (keeping current: " << age << ")" << endl;
}
}
void setFirstName(const string& fn) {
if (!fn.empty()) {
firstName = fn;
}
}
void setLastName(const string& ln) {
if (!ln.empty()) {
lastName = ln;
}
}
};
void demonstrateGettersSetters() {
cout << "\n--- Getters and Setters ---\n" << endl;
Person p("John", "Doe", 30);
cout << "Person: " << p.getFullName() << ", Age: " << p.getAge() << endl;
// Valid update
p.setAge(31);
cout << "After setAge(31): " << p.getAge() << endl;
// Invalid update - rejected
p.setAge(-5);
cout << "After setAge(-5): " << p.getAge() << " (unchanged)" << endl;
p.setAge(200);
cout << "After setAge(200): " << p.getAge() << " (unchanged)" << endl;
// Update name
p.setFirstName("Jane");
cout << "After setFirstName(\"Jane\"): " << p.getFullName() << endl;
}
// ============================================================
// SECTION 4: REFERENCE GETTERS
// ============================================================
class DataContainer {
private:
vector<int> data;
string label;
public:
DataContainer(const string& lbl) : label(lbl) {}
// Add data
void add(int value) {
data.push_back(value);
}
// Const reference getter - efficient, read-only
const vector<int>& getData() const {
return data;
}
// Non-const reference getter - allows modification
vector<int>& getDataMutable() {
return data;
}
// Copy getter - less efficient but safer
vector<int> getDataCopy() const {
return data; // Returns a copy
}
const string& getLabel() const {
return label;
}
};
void demonstrateReferenceGetters() {
cout << "\n--- Reference Getters ---\n" << endl;
DataContainer container("My Data");
container.add(10);
container.add(20);
container.add(30);
// Read via const reference (efficient)
cout << "Data (const ref): ";
for (int val : container.getData()) {
cout << val << " ";
}
cout << endl;
// Modify via mutable reference
container.getDataMutable().push_back(40);
container.getDataMutable()[0] = 100;
cout << "After modification: ";
for (int val : container.getData()) {
cout << val << " ";
}
cout << endl;
// Copy - modifications don't affect original
vector<int> copy = container.getDataCopy();
copy.push_back(999);
cout << "Copy has: " << copy.size() << " elements" << endl;
cout << "Original has: " << container.getData().size() << " elements" << endl;
}
// ============================================================
// SECTION 5: VALIDATION AND INVARIANTS
// ============================================================
class Rectangle {
private:
double width;
double height;
// Invariant: width and height are always positive
void validateDimension(double& dim, double value, const string& name) {
if (value > 0) {
dim = value;
} else {
cout << " Invalid " << name << ": " << value << " (must be positive)" << endl;
}
}
public:
Rectangle(double w, double h) : width(1), height(1) {
setWidth(w);
setHeight(h);
}
double getWidth() const { return width; }
double getHeight() const { return height; }
void setWidth(double w) { validateDimension(width, w, "width"); }
void setHeight(double h) { validateDimension(height, h, "height"); }
double getArea() const { return width * height; }
double getPerimeter() const { return 2 * (width + height); }
};
class Fraction {
private:
int numerator;
int denominator;
static int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
// Invariant: denominator > 0, fraction is reduced
void normalize() {
if (denominator < 0) {
numerator = -numerator;
denominator = -denominator;
}
int g = gcd(abs(numerator), denominator);
if (g > 0) {
numerator /= g;
denominator /= g;
}
}
public:
Fraction(int num, int den) : numerator(num), denominator(1) {
if (den == 0) {
throw invalid_argument("Denominator cannot be zero");
}
denominator = den;
normalize();
}
int getNumerator() const { return numerator; }
int getDenominator() const { return denominator; }
double toDouble() const {
return static_cast<double>(numerator) / denominator;
}
void display() const {
cout << numerator << "/" << denominator;
}
};
void demonstrateValidation() {
cout << "\n--- Validation and Invariants ---\n" << endl;
cout << "Rectangle with validation:" << endl;
Rectangle r(5.0, 3.0);
cout << "Rectangle: " << r.getWidth() << " x " << r.getHeight() << endl;
r.setWidth(-10); // Invalid
r.setHeight(0); // Invalid
cout << "After invalid setters: " << r.getWidth() << " x " << r.getHeight() << endl;
cout << "\nFraction with invariant (always reduced):" << endl;
Fraction f1(4, 8);
cout << "4/8 normalized: ";
f1.display();
cout << " = " << f1.toDouble() << endl;
Fraction f2(-3, -9);
cout << "-3/-9 normalized: ";
f2.display();
cout << endl;
Fraction f3(5, -10);
cout << "5/-10 normalized: ";
f3.display();
cout << endl;
try {
Fraction bad(1, 0); // Will throw
} catch (const invalid_argument& e) {
cout << "Exception: " << e.what() << endl;
}
}
// ============================================================
// SECTION 6: FRIEND FUNCTIONS
// ============================================================
class Vector2D {
private:
double x, y;
public:
Vector2D(double xVal = 0, double yVal = 0) : x(xVal), y(yVal) {}
double getX() const { return x; }
double getY() const { return y; }
// Friend function for dot product
friend double dotProduct(const Vector2D& a, const Vector2D& b);
// Friend for operator<<
friend ostream& operator<<(ostream& os, const Vector2D& v);
};
// Friend function implementation
double dotProduct(const Vector2D& a, const Vector2D& b) {
return a.x * b.x + a.y * b.y; // Direct access to private members
}
ostream& operator<<(ostream& os, const Vector2D& v) {
os << "(" << v.x << ", " << v.y << ")";
return os;
}
void demonstrateFriendFunctions() {
cout << "\n--- Friend Functions ---\n" << endl;
Vector2D v1(3, 4);
Vector2D v2(1, 2);
cout << "v1 = " << v1 << endl;
cout << "v2 = " << v2 << endl;
cout << "Dot product: " << dotProduct(v1, v2) << endl;
}
// ============================================================
// SECTION 7: FRIEND CLASSES
// ============================================================
class Engine {
private:
int horsepower;
int rpm;
bool running;
friend class Mechanic; // Mechanic can access everything
public:
Engine(int hp) : horsepower(hp), rpm(0), running(false) {}
bool isRunning() const { return running; }
int getRPM() const { return rpm; }
void start() {
if (!running) {
running = true;
rpm = 800; // Idle
cout << "Engine started (idle at " << rpm << " RPM)" << endl;
}
}
void stop() {
running = false;
rpm = 0;
cout << "Engine stopped" << endl;
}
};
class Mechanic {
public:
// Can access Engine's private members
void diagnose(const Engine& e) {
cout << "Mechanic diagnosis:" << endl;
cout << " Horsepower: " << e.horsepower << endl;
cout << " RPM: " << e.rpm << endl;
cout << " Running: " << (e.running ? "Yes" : "No") << endl;
}
void repair(Engine& e, int newHP) {
cout << "Mechanic upgrading engine from " << e.horsepower
<< "hp to " << newHP << "hp" << endl;
e.horsepower = newHP; // Direct access
}
};
void demonstrateFriendClasses() {
cout << "\n--- Friend Classes ---\n" << endl;
Engine engine(200);
Mechanic mechanic;
mechanic.diagnose(engine);
cout << endl;
engine.start();
mechanic.diagnose(engine);
cout << endl;
mechanic.repair(engine, 250);
mechanic.diagnose(engine);
}
// ============================================================
// SECTION 8: IMMUTABLE CLASS
// ============================================================
class ImmutablePoint {
private:
const double x;
const double y;
public:
ImmutablePoint(double xVal, double yVal) : x(xVal), y(yVal) {}
double getX() const { return x; }
double getY() const { return y; }
// Cannot modify - return new object instead
ImmutablePoint translate(double dx, double dy) const {
return ImmutablePoint(x + dx, y + dy);
}
ImmutablePoint scale(double factor) const {
return ImmutablePoint(x * factor, y * factor);
}
double distanceTo(const ImmutablePoint& other) const {
double dx = x - other.x;
double dy = y - other.y;
return sqrt(dx * dx + dy * dy);
}
friend ostream& operator<<(ostream& os, const ImmutablePoint& p) {
return os << "(" << p.x << ", " << p.y << ")";
}
};
void demonstrateImmutability() {
cout << "\n--- Immutable Class ---\n" << endl;
ImmutablePoint p1(3, 4);
cout << "Original point: " << p1 << endl;
// Operations return new objects
ImmutablePoint p2 = p1.translate(1, 2);
cout << "After translate(1, 2): " << p2 << endl;
cout << "Original unchanged: " << p1 << endl;
ImmutablePoint p3 = p1.scale(2);
cout << "After scale(2): " << p3 << endl;
cout << "Distance from p1 to p2: " << p1.distanceTo(p2) << endl;
}
// ============================================================
// SECTION 9: COMPLETE ENCAPSULATED CLASS
// ============================================================
class Employee {
private:
static int nextId;
const int id;
string name;
string department;
double salary;
// Private validation
bool isValidSalary(double s) const {
return s >= 0;
}
public:
Employee(const string& n, const string& dept, double sal)
: id(nextId++), name(n), department(dept), salary(0) {
setSalary(sal);
}
// Getters
int getId() const { return id; }
const string& getName() const { return name; }
const string& getDepartment() const { return department; }
double getSalary() const { return salary; }
// Setters with validation
void setName(const string& n) {
if (!n.empty()) name = n;
}
void setDepartment(const string& dept) {
if (!dept.empty()) department = dept;
}
void setSalary(double s) {
if (isValidSalary(s)) {
salary = s;
} else {
cout << "Invalid salary for " << name << endl;
}
}
// Operations
void giveRaise(double percent) {
if (percent > 0) {
salary *= (1 + percent / 100);
cout << name << " received " << percent << "% raise" << endl;
}
}
// Display
friend ostream& operator<<(ostream& os, const Employee& e) {
os << "Employee #" << e.id << ": " << e.name
<< " (" << e.department << ") - $" << e.salary;
return os;
}
};
int Employee::nextId = 1000;
void demonstrateCompleteExample() {
cout << "\n--- Complete Encapsulated Class ---\n" << endl;
Employee emp1("Alice Smith", "Engineering", 75000);
Employee emp2("Bob Johnson", "Marketing", 65000);
cout << emp1 << endl;
cout << emp2 << endl;
cout << endl;
emp1.giveRaise(10);
cout << emp1 << endl;
emp2.setDepartment("Sales");
cout << emp2 << endl;
emp1.setSalary(-1000); // Invalid - will be rejected
}
// ============================================================
// MAIN FUNCTION
// ============================================================
int main() {
cout << "╔════════════════════════════════════════════════════════════════════╗" << endl;
cout << "║ C++ ENCAPSULATION - EXAMPLES ║" << endl;
cout << "║ Data Protection and Access Control ║" << endl;
cout << "╚════════════════════════════════════════════════════════════════════╝" << endl;
cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
cout << "║ SECTION 1: Basic Encapsulation ║" << endl;
cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
demonstrateBasicEncapsulation();
cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
cout << "║ SECTION 2: Access Modifiers ║" << endl;
cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
demonstrateAccessModifiers();
cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
cout << "║ SECTION 3: Getters and Setters ║" << endl;
cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
demonstrateGettersSetters();
cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
cout << "║ SECTION 4: Reference Getters ║" << endl;
cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
demonstrateReferenceGetters();
cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
cout << "║ SECTION 5: Validation and Invariants ║" << endl;
cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
demonstrateValidation();
cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
cout << "║ SECTION 6: Friend Functions ║" << endl;
cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
demonstrateFriendFunctions();
cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
cout << "║ SECTION 7: Friend Classes ║" << endl;
cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
demonstrateFriendClasses();
cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
cout << "║ SECTION 8: Immutable Class ║" << endl;
cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
demonstrateImmutability();
cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
cout << "║ SECTION 9: Complete Example ║" << endl;
cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
demonstrateCompleteExample();
cout << "\n╔════════════════════════════════════════════════════════════════════╗" << endl;
cout << "║ Examples Complete! ║" << endl;
cout << "╚════════════════════════════════════════════════════════════════════╝" << endl;
return 0;
}