cpp
examples
examples.cpp⚙️cpp
/**
* Friend Functions, Friend Classes & Functors - Examples
* Comprehensive demonstrations of C++ friendship and callable objects
*/
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <numeric>
#include <functional>
#include <map>
#include <iomanip>
using std::cout;
using std::endl;
using std::string;
// ============================================================================
// SECTION 1: Friend Function Basics
// ============================================================================
class Box {
private:
double width;
double height;
double depth;
public:
Box(double w, double h, double d) : width(w), height(h), depth(d) {}
// Declare friend function - can access private members
friend double calculateVolume(const Box& box);
friend void printDimensions(const Box& box);
// Friend function for comparing two boxes
friend bool areSameSize(const Box& a, const Box& b);
};
// Friend function implementations (NOT member functions!)
double calculateVolume(const Box& box) {
// Can access private members
return box.width * box.height * box.depth;
}
void printDimensions(const Box& box) {
cout << " Box: " << box.width << " x " << box.height << " x " << box.depth << endl;
}
bool areSameSize(const Box& a, const Box& b) {
return a.width == b.width &&
a.height == b.height &&
a.depth == b.depth;
}
void demonstrateFriendFunctions() {
cout << "\n=== FRIEND FUNCTION BASICS ===" << endl;
Box box1(3.0, 4.0, 5.0);
Box box2(3.0, 4.0, 5.0);
Box box3(2.0, 2.0, 2.0);
cout << "\nBox 1:" << endl;
printDimensions(box1);
cout << " Volume: " << calculateVolume(box1) << endl;
cout << "\nBox 3:" << endl;
printDimensions(box3);
cout << " Volume: " << calculateVolume(box3) << endl;
cout << "\nComparisons:" << endl;
cout << " Box1 same size as Box2: " << (areSameSize(box1, box2) ? "Yes" : "No") << endl;
cout << " Box1 same size as Box3: " << (areSameSize(box1, box3) ? "Yes" : "No") << endl;
}
// ============================================================================
// SECTION 2: Friend Function for Operator Overloading
// ============================================================================
class Complex {
private:
double real;
double imag;
public:
Complex(double r = 0, double i = 0) : real(r), imag(i) {}
// Member function for addition (left operand is Complex)
Complex operator+(const Complex& other) const {
return Complex(real + other.real, imag + other.imag);
}
// Friend for stream output (left operand is ostream)
friend std::ostream& operator<<(std::ostream& os, const Complex& c);
// Friend for stream input
friend std::istream& operator>>(std::istream& is, Complex& c);
// Friend for scalar multiplication (scalar on left)
friend Complex operator*(double scalar, const Complex& c);
// Friend for equality comparison
friend bool operator==(const Complex& a, const Complex& b);
};
std::ostream& operator<<(std::ostream& os, const Complex& c) {
os << c.real;
if (c.imag >= 0) os << "+";
os << c.imag << "i";
return os;
}
std::istream& operator>>(std::istream& is, Complex& c) {
is >> c.real >> c.imag;
return is;
}
Complex operator*(double scalar, const Complex& c) {
return Complex(scalar * c.real, scalar * c.imag);
}
bool operator==(const Complex& a, const Complex& b) {
return a.real == b.real && a.imag == b.imag;
}
void demonstrateOperatorOverloading() {
cout << "\n=== FRIEND FUNCTION FOR OPERATORS ===" << endl;
Complex a(3, 4);
Complex b(1, -2);
cout << "\nComplex numbers:" << endl;
cout << " a = " << a << endl;
cout << " b = " << b << endl;
cout << "\nOperations:" << endl;
cout << " a + b = " << (a + b) << endl;
cout << " 2.5 * a = " << (2.5 * a) << endl; // Friend function (scalar on left)
cout << " a == b: " << (a == b ? "true" : "false") << endl;
Complex c(3, 4);
cout << " a == c: " << (a == c ? "true" : "false") << endl;
}
// ============================================================================
// SECTION 3: Friend Class
// ============================================================================
// Forward declaration
class BankAccount;
class BankAuditor {
public:
void audit(const BankAccount& account);
void setBalance(BankAccount& account, double newBalance);
};
class BankAccount {
private:
string owner;
double balance;
string accountNumber;
std::vector<string> transactions;
public:
BankAccount(string name, string accNum, double initial)
: owner(name), accountNumber(accNum), balance(initial) {
transactions.push_back("Initial deposit: $" + std::to_string(initial));
}
void deposit(double amount) {
if (amount > 0) {
balance += amount;
transactions.push_back("Deposit: $" + std::to_string(amount));
}
}
bool withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
transactions.push_back("Withdrawal: $" + std::to_string(amount));
return true;
}
return false;
}
double getBalance() const { return balance; }
// BankAuditor can access ALL private members
friend class BankAuditor;
};
void BankAuditor::audit(const BankAccount& account) {
cout << "\n === AUDIT REPORT ===" << endl;
cout << " Account: " << account.accountNumber << endl;
cout << " Owner: " << account.owner << endl;
cout << " Balance: $" << std::fixed << std::setprecision(2) << account.balance << endl;
cout << " Transaction History:" << endl;
for (const auto& t : account.transactions) {
cout << " - " << t << endl;
}
}
void BankAuditor::setBalance(BankAccount& account, double newBalance) {
// Auditor can modify private data - use responsibly!
account.balance = newBalance;
account.transactions.push_back("Audit adjustment to: $" + std::to_string(newBalance));
}
void demonstrateFriendClass() {
cout << "\n=== FRIEND CLASS ===" << endl;
BankAccount account("John Doe", "ACC-12345", 1000.0);
account.deposit(500);
account.withdraw(200);
BankAuditor auditor;
auditor.audit(account);
cout << "\n Auditor making correction..." << endl;
auditor.setBalance(account, 1350.0);
auditor.audit(account);
}
// ============================================================================
// SECTION 4: Friendship Properties Demo
// ============================================================================
class A; // Forward declaration
class B {
public:
void accessA(A& a);
};
class A {
private:
int secretA = 42;
public:
friend class B; // B can access A's private
// A does NOT have access to B's private!
};
class C : public B {
// C is NOT automatically a friend of A!
// Friendship is NOT inherited
};
void B::accessA(A& a) {
cout << " B accessing A's secret: " << a.secretA << endl;
}
void demonstrateFriendshipProperties() {
cout << "\n=== FRIENDSHIP PROPERTIES ===" << endl;
A objA;
B objB;
cout << "\n1. Friendship grants access:" << endl;
objB.accessA(objA);
cout << "\n2. Friendship is NOT symmetric:" << endl;
cout << " B can access A's private members" << endl;
cout << " But A cannot access B's private members" << endl;
cout << "\n3. Friendship is NOT inherited:" << endl;
cout << " C inherits from B, but C is NOT a friend of A" << endl;
cout << "\n4. Friendship is NOT transitive:" << endl;
cout << " If A friends B, and B friends C, C is NOT a friend of A" << endl;
}
// ============================================================================
// SECTION 5: Basic Functor
// ============================================================================
class Adder {
int value;
public:
Adder(int v) : value(v) {
cout << " [Adder] Created with value " << value << endl;
}
// This makes it callable like a function
int operator()(int x) const {
return x + value;
}
};
class Multiplier {
int factor;
public:
Multiplier(int f) : factor(f) {}
int operator()(int x) const {
return x * factor;
}
};
void demonstrateBasicFunctor() {
cout << "\n=== BASIC FUNCTOR ===" << endl;
cout << "\nCreating functors:" << endl;
Adder add5(5);
Adder add10(10);
Multiplier times3(3);
cout << "\nUsing functors like functions:" << endl;
cout << " add5(20) = " << add5(20) << endl;
cout << " add10(20) = " << add10(20) << endl;
cout << " times3(20) = " << times3(20) << endl;
cout << "\nFunctors with different state produce different results!" << endl;
}
// ============================================================================
// SECTION 6: Functor with State
// ============================================================================
class Counter {
int count = 0;
public:
void operator()() {
++count;
}
int getCount() const { return count; }
};
class RunningStats {
double sum = 0;
double sumSquares = 0;
int count = 0;
public:
void operator()(double value) {
sum += value;
sumSquares += value * value;
++count;
}
double mean() const {
return count > 0 ? sum / count : 0;
}
double variance() const {
if (count < 2) return 0;
double m = mean();
return (sumSquares / count) - (m * m);
}
int getCount() const { return count; }
};
void demonstrateStatefulFunctor() {
cout << "\n=== STATEFUL FUNCTOR ===" << endl;
cout << "\n1. Counter functor:" << endl;
Counter counter;
counter();
counter();
counter();
cout << " Called 3 times, count = " << counter.getCount() << endl;
cout << "\n2. Running statistics functor:" << endl;
RunningStats stats;
std::vector<double> values = {10, 20, 30, 40, 50};
for (double v : values) {
stats(v); // Call functor
}
cout << " Values: 10, 20, 30, 40, 50" << endl;
cout << " Count: " << stats.getCount() << endl;
cout << " Mean: " << stats.mean() << endl;
cout << " Variance: " << stats.variance() << endl;
}
// ============================================================================
// SECTION 7: Functors with STL Algorithms
// ============================================================================
struct IsEven {
bool operator()(int n) const {
return n % 2 == 0;
}
};
struct IsGreaterThan {
int threshold;
IsGreaterThan(int t) : threshold(t) {}
bool operator()(int n) const {
return n > threshold;
}
};
struct PrintElement {
void operator()(int n) const {
cout << n << " ";
}
};
struct Square {
int operator()(int n) const {
return n * n;
}
};
void demonstrateFunctorsWithSTL() {
cout << "\n=== FUNCTORS WITH STL ALGORITHMS ===" << endl;
std::vector<int> nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
cout << "\nOriginal: ";
std::for_each(nums.begin(), nums.end(), PrintElement());
cout << endl;
// Count even numbers
int evenCount = std::count_if(nums.begin(), nums.end(), IsEven());
cout << "Even numbers: " << evenCount << endl;
// Count numbers > 5
int gt5Count = std::count_if(nums.begin(), nums.end(), IsGreaterThan(5));
cout << "Numbers > 5: " << gt5Count << endl;
// Transform to squares
std::vector<int> squares(nums.size());
std::transform(nums.begin(), nums.end(), squares.begin(), Square());
cout << "Squares: ";
std::for_each(squares.begin(), squares.end(), PrintElement());
cout << endl;
// Remove even numbers
auto newEnd = std::remove_if(nums.begin(), nums.end(), IsEven());
nums.erase(newEnd, nums.end());
cout << "After removing evens: ";
std::for_each(nums.begin(), nums.end(), PrintElement());
cout << endl;
}
// ============================================================================
// SECTION 8: STL Predefined Functors
// ============================================================================
void demonstrateSTLFunctors() {
cout << "\n=== STL PREDEFINED FUNCTORS ===" << endl;
std::vector<int> nums = {5, 2, 8, 1, 9, 3, 7, 4, 6};
cout << "\nOriginal: ";
for (int n : nums) cout << n << " ";
cout << endl;
// Sort ascending (default)
std::sort(nums.begin(), nums.end());
cout << "Ascending: ";
for (int n : nums) cout << n << " ";
cout << endl;
// Sort descending using std::greater
std::sort(nums.begin(), nums.end(), std::greater<int>());
cout << "Descending: ";
for (int n : nums) cout << n << " ";
cout << endl;
// Accumulate with multiplication
int product = std::accumulate(nums.begin(), nums.end(), 1, std::multiplies<int>());
cout << "Product of all: " << product << endl;
// Find using std::equal_to
nums = {1, 2, 3, 4, 5};
auto it = std::find_if(nums.begin(), nums.end(),
std::bind(std::equal_to<int>(), std::placeholders::_1, 3));
if (it != nums.end()) {
cout << "Found 3 at position " << (it - nums.begin()) << endl;
}
// Negate all elements
std::vector<int> negated(nums.size());
std::transform(nums.begin(), nums.end(), negated.begin(), std::negate<int>());
cout << "Negated: ";
for (int n : negated) cout << n << " ";
cout << endl;
}
// ============================================================================
// SECTION 9: Functors vs Lambdas
// ============================================================================
void demonstrateFunctorsVsLambdas() {
cout << "\n=== FUNCTORS vs LAMBDAS ===" << endl;
std::vector<int> nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// Functor approach
cout << "\n1. Using functor (IsEven):" << endl;
int evenFunctor = std::count_if(nums.begin(), nums.end(), IsEven());
cout << " Even count: " << evenFunctor << endl;
// Lambda approach (equivalent)
cout << "\n2. Using lambda:" << endl;
int evenLambda = std::count_if(nums.begin(), nums.end(),
[](int n) { return n % 2 == 0; });
cout << " Even count: " << evenLambda << endl;
// Functor with state
cout << "\n3. Functor with state (threshold):" << endl;
int threshold = 5;
int gtFunctor = std::count_if(nums.begin(), nums.end(), IsGreaterThan(threshold));
cout << " Count > " << threshold << ": " << gtFunctor << endl;
// Lambda capturing state
cout << "\n4. Lambda capturing state:" << endl;
int gtLambda = std::count_if(nums.begin(), nums.end(),
[threshold](int n) { return n > threshold; });
cout << " Count > " << threshold << ": " << gtLambda << endl;
cout << "\nNote: Lambdas are actually anonymous functor classes!" << endl;
}
// ============================================================================
// SECTION 10: std::function and Functors
// ============================================================================
class Calculator {
std::map<string, std::function<double(double, double)>> operations;
public:
Calculator() {
// Use functors
operations["add"] = std::plus<double>();
operations["sub"] = std::minus<double>();
operations["mul"] = std::multiplies<double>();
operations["div"] = std::divides<double>();
// Custom lambda
operations["pow"] = [](double a, double b) {
double result = 1;
for (int i = 0; i < static_cast<int>(b); ++i) {
result *= a;
}
return result;
};
}
double calculate(const string& op, double a, double b) {
if (operations.find(op) != operations.end()) {
return operations[op](a, b);
}
throw std::runtime_error("Unknown operation: " + op);
}
};
void demonstrateFunctionWrapper() {
cout << "\n=== std::function WITH FUNCTORS ===" << endl;
Calculator calc;
cout << "\n1. Using stored operations:" << endl;
cout << " 5 + 3 = " << calc.calculate("add", 5, 3) << endl;
cout << " 5 - 3 = " << calc.calculate("sub", 5, 3) << endl;
cout << " 5 * 3 = " << calc.calculate("mul", 5, 3) << endl;
cout << " 5 / 3 = " << calc.calculate("div", 5, 3) << endl;
cout << " 2 ^ 8 = " << calc.calculate("pow", 2, 8) << endl;
cout << "\n2. std::function can hold:" << endl;
cout << " - Regular functions" << endl;
cout << " - Functors" << endl;
cout << " - Lambda expressions" << endl;
cout << " - std::bind expressions" << endl;
}
// ============================================================================
// SECTION 11: Practical Example - Filter Pipeline
// ============================================================================
template<typename Container, typename... Predicates>
Container filterAll(const Container& input, Predicates... predicates) {
Container result;
for (const auto& item : input) {
bool passesAll = (predicates(item) && ...); // C++17 fold expression
if (passesAll) {
result.push_back(item);
}
}
return result;
}
struct IsPositive {
bool operator()(int n) const { return n > 0; }
};
struct IsLessThan {
int limit;
IsLessThan(int l) : limit(l) {}
bool operator()(int n) const { return n < limit; }
};
void demonstratePracticalExample() {
cout << "\n=== PRACTICAL EXAMPLE: FILTER PIPELINE ===" << endl;
std::vector<int> nums = {-5, 10, 3, -2, 8, 15, 7, -1, 20, 4};
cout << "\nOriginal: ";
for (int n : nums) cout << n << " ";
cout << endl;
// Filter: positive AND less than 10
auto filtered = filterAll(nums, IsPositive(), IsLessThan(10));
cout << "Positive AND < 10: ";
for (int n : filtered) cout << n << " ";
cout << endl;
// Using with lambdas
auto filtered2 = filterAll(nums,
[](int n) { return n > 0; },
[](int n) { return n % 2 == 0; });
cout << "Positive AND even: ";
for (int n : filtered2) cout << n << " ";
cout << endl;
}
// ============================================================================
// SECTION 12: Friend Functions in Templates
// ============================================================================
template<typename T>
class Container {
T value;
public:
Container(T v) : value(v) {}
// Friend function template
template<typename U>
friend std::ostream& operator<<(std::ostream& os, const Container<U>& c);
// Friend function for same type
friend bool operator==(const Container& a, const Container& b) {
return a.value == b.value;
}
};
template<typename U>
std::ostream& operator<<(std::ostream& os, const Container<U>& c) {
return os << "Container(" << c.value << ")";
}
void demonstrateTemplateFriends() {
cout << "\n=== FRIEND FUNCTIONS IN TEMPLATES ===" << endl;
Container<int> c1(42);
Container<int> c2(42);
Container<string> c3("Hello");
cout << "\n1. Stream output friend:" << endl;
cout << " " << c1 << endl;
cout << " " << c3 << endl;
cout << "\n2. Equality friend:" << endl;
cout << " c1 == c2: " << (c1 == c2 ? "true" : "false") << endl;
}
// ============================================================================
// MAIN
// ============================================================================
int main() {
cout << "╔══════════════════════════════════════════════════════════════╗" << endl;
cout << "║ FRIEND FUNCTIONS, FRIEND CLASSES & FUNCTORS EXAMPLES ║" << endl;
cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
demonstrateFriendFunctions();
demonstrateOperatorOverloading();
demonstrateFriendClass();
demonstrateFriendshipProperties();
demonstrateBasicFunctor();
demonstrateStatefulFunctor();
demonstrateFunctorsWithSTL();
demonstrateSTLFunctors();
demonstrateFunctorsVsLambdas();
demonstrateFunctionWrapper();
demonstratePracticalExample();
demonstrateTemplateFriends();
cout << "\n═══════════════════════════════════════════════════════════════" << endl;
cout << "All examples completed!" << endl;
return 0;
}