cpp

exercises

exercises.cpp⚙️
/**
 * Friend Functions, Friend Classes & Functors - Exercises
 * Practice problems for C++ friendship and callable objects
 */

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>
#include <cassert>

using std::cout;
using std::endl;
using std::string;

// ============================================================================
// EXERCISE 1: Implement Friend Function
// ============================================================================

/**
 * TODO: Create a Distance class representing distance in meters.
 * Implement friend function to add two Distance objects.
 * 
 * Requirements:
 * 1. Private member 'meters' (double)
 * 2. Constructor taking meters
 * 3. Friend function: Distance add(const Distance& a, const Distance& b)
 * 4. Friend function for stream output
 */

class Distance {
    // TODO: Add private member
    
public:
    // TODO: Add constructor
    
    // TODO: Declare friend functions
};

// TODO: Implement friend functions

void testExercise1() {
    cout << "=== EXERCISE 1: Friend Function ===" << endl;
    
    /*
    Distance d1(100.5);
    Distance d2(50.25);
    Distance d3 = add(d1, d2);
    
    cout << "  d1: " << d1 << endl;
    cout << "  d2: " << d2 << endl;
    cout << "  d1 + d2: " << d3 << endl;
    
    cout << "Exercise 1 PASSED!" << endl;
    */
    
    cout << "Uncomment test code after implementation" << endl;
}

// ============================================================================
// EXERCISE 2: Implement Stream Operators
// ============================================================================

/**
 * TODO: Create a Fraction class with numerator and denominator.
 * Implement friend stream operators.
 * 
 * Requirements:
 * 1. Private members: numerator, denominator (both int)
 * 2. Friend operator<< to output as "n/d"
 * 3. Friend operator>> to input as "n d" (space separated)
 * 4. Friend comparison operators (==, <)
 */

class Fraction {
    // TODO: Add private members
    
public:
    // TODO: Add constructor(s)
    
    // TODO: Declare friend operators
};

// TODO: Implement friend operators

void testExercise2() {
    cout << "\n=== EXERCISE 2: Stream Operators ===" << endl;
    
    /*
    Fraction f1(3, 4);
    Fraction f2(1, 2);
    
    cout << "  f1 = " << f1 << endl;
    cout << "  f2 = " << f2 << endl;
    
    cout << "  f1 == f2: " << (f1 == f2 ? "true" : "false") << endl;
    cout << "  f1 < f2: " << (f1 < f2 ? "true" : "false") << endl;
    
    // Test input (from stringstream if needed)
    
    cout << "Exercise 2 PASSED!" << endl;
    */
    
    cout << "Uncomment test code after implementation" << endl;
}

// ============================================================================
// EXERCISE 3: Friend Class Implementation
// ============================================================================

/**
 * TODO: Create a PasswordManager that has friend access to UserAccount.
 * 
 * Requirements:
 * 1. UserAccount with private: username, passwordHash, loginAttempts
 * 2. PasswordManager as friend class
 * 3. PasswordManager can reset password, check attempts, lock account
 * 4. UserAccount cannot be modified except through PasswordManager
 */

class UserAccount {
    // TODO: Add private members
    // string username;
    // size_t passwordHash;
    // int loginAttempts;
    // bool locked;
    
public:
    // TODO: Constructor (username, initial password)
    
    // TODO: bool login(const string& password)
    
    // TODO: Declare friend class
};

class PasswordManager {
public:
    // TODO: void resetPassword(UserAccount& acc, const string& newPass)
    
    // TODO: void unlockAccount(UserAccount& acc)
    
    // TODO: int getFailedAttempts(const UserAccount& acc)
    
    // TODO: void forceLogout(UserAccount& acc)
};

void testExercise3() {
    cout << "\n=== EXERCISE 3: Friend Class ===" << endl;
    
    /*
    UserAccount user("john_doe", "secret123");
    PasswordManager pm;
    
    // Test login
    assert(user.login("secret123") == true);
    assert(user.login("wrong") == false);
    
    // Test password reset (friend access)
    pm.resetPassword(user, "newpass456");
    assert(user.login("newpass456") == true);
    
    // Test failed attempts tracking
    user.login("wrong1");
    user.login("wrong2");
    cout << "  Failed attempts: " << pm.getFailedAttempts(user) << endl;
    
    // Test unlock
    pm.unlockAccount(user);
    cout << "  Account unlocked" << endl;
    
    cout << "Exercise 3 PASSED!" << endl;
    */
    
    cout << "Uncomment test code after implementation" << endl;
}

// ============================================================================
// EXERCISE 4: Basic Functor
// ============================================================================

/**
 * TODO: Create a functor that scales numbers by a given factor.
 * 
 * Requirements:
 * 1. Store scale factor as member
 * 2. operator() takes a number and returns scaled value
 * 3. Works with std::transform
 */

class Scaler {
    // TODO: Add member
    
public:
    // TODO: Add constructor
    
    // TODO: Add operator()
};

void testExercise4() {
    cout << "\n=== EXERCISE 4: Basic Functor ===" << endl;
    
    /*
    std::vector<double> values = {1.0, 2.0, 3.0, 4.0, 5.0};
    std::vector<double> scaled(values.size());
    
    // Scale by 2.5
    Scaler scale25(2.5);
    std::transform(values.begin(), values.end(), scaled.begin(), scale25);
    
    cout << "  Original: ";
    for (double v : values) cout << v << " ";
    cout << endl;
    
    cout << "  Scaled x2.5: ";
    for (double v : scaled) cout << v << " ";
    cout << endl;
    
    // Verify
    assert(scaled[0] == 2.5);
    assert(scaled[4] == 12.5);
    
    cout << "Exercise 4 PASSED!" << endl;
    */
    
    cout << "Uncomment test code after implementation" << endl;
}

// ============================================================================
// EXERCISE 5: Predicate Functor
// ============================================================================

/**
 * TODO: Create a functor that checks if a string matches a pattern.
 * 
 * Requirements:
 * 1. Store pattern string
 * 2. operator() returns true if input contains pattern
 * 3. Works with std::count_if and std::remove_if
 */

class ContainsPattern {
    // TODO: Add member
    
public:
    // TODO: Add constructor
    
    // TODO: Add operator()
};

void testExercise5() {
    cout << "\n=== EXERCISE 5: Predicate Functor ===" << endl;
    
    /*
    std::vector<string> words = {
        "hello", "world", "hello_world", "hi", "help", "yellow"
    };
    
    ContainsPattern hasHello("ello");
    
    int count = std::count_if(words.begin(), words.end(), hasHello);
    cout << "  Words containing 'ello': " << count << endl;
    assert(count == 3);  // hello, hello_world, yellow
    
    // Find first match
    auto it = std::find_if(words.begin(), words.end(), hasHello);
    cout << "  First match: " << *it << endl;
    
    cout << "Exercise 5 PASSED!" << endl;
    */
    
    cout << "Uncomment test code after implementation" << endl;
}

// ============================================================================
// EXERCISE 6: Stateful Functor - Counter
// ============================================================================

/**
 * TODO: Create a functor that counts how many times it's called
 * and tracks min/max values seen.
 * 
 * Requirements:
 * 1. Track count, min, max values
 * 2. operator() updates stats and returns the value
 * 3. Provide getters for count, min, max
 */

class StatTracker {
    // TODO: Add members
    
public:
    // TODO: Constructor
    
    // TODO: operator()(int value)
    
    // TODO: getCount(), getMin(), getMax()
};

void testExercise6() {
    cout << "\n=== EXERCISE 6: Stateful Functor ===" << endl;
    
    /*
    std::vector<int> nums = {5, 2, 8, 1, 9, 3};
    StatTracker tracker;
    
    std::for_each(nums.begin(), nums.end(), std::ref(tracker));
    
    cout << "  Count: " << tracker.getCount() << endl;
    cout << "  Min: " << tracker.getMin() << endl;
    cout << "  Max: " << tracker.getMax() << endl;
    
    assert(tracker.getCount() == 6);
    assert(tracker.getMin() == 1);
    assert(tracker.getMax() == 9);
    
    cout << "Exercise 6 PASSED!" << endl;
    */
    
    cout << "Uncomment test code after implementation" << endl;
}

// ============================================================================
// EXERCISE 7: Composable Functors
// ============================================================================

/**
 * TODO: Create a Compose class that combines two functors.
 * Result: compose(f, g)(x) = f(g(x))
 * 
 * Requirements:
 * 1. Store two function objects
 * 2. operator() calls g first, then f on result
 * 3. Works with any callable (functors, lambdas)
 */

template<typename F, typename G>
class Compose {
    // TODO: Add members
    
public:
    // TODO: Constructor
    
    // TODO: operator()
};

// Helper function to create Compose
template<typename F, typename G>
Compose<F, G> compose(F f, G g) {
    return Compose<F, G>(f, g);
}

void testExercise7() {
    cout << "\n=== EXERCISE 7: Composable Functors ===" << endl;
    
    /*
    auto addOne = [](int x) { return x + 1; };
    auto timesTwo = [](int x) { return x * 2; };
    
    // compose(addOne, timesTwo)(5) = addOne(timesTwo(5)) = addOne(10) = 11
    auto addAfterDouble = compose(addOne, timesTwo);
    int result = addAfterDouble(5);
    
    cout << "  (x * 2) + 1 where x = 5: " << result << endl;
    assert(result == 11);
    
    // compose(timesTwo, addOne)(5) = timesTwo(addOne(5)) = timesTwo(6) = 12
    auto doubleAfterAdd = compose(timesTwo, addOne);
    result = doubleAfterAdd(5);
    
    cout << "  (x + 1) * 2 where x = 5: " << result << endl;
    assert(result == 12);
    
    cout << "Exercise 7 PASSED!" << endl;
    */
    
    cout << "Uncomment test code after implementation" << endl;
}

// ============================================================================
// EXERCISE 8: Binary Functor with STL
// ============================================================================

/**
 * TODO: Create a WeightedSum functor for std::accumulate.
 * 
 * Requirements:
 * 1. Store weight factor
 * 2. operator()(sum, value) returns sum + value * weight
 * 3. Use with std::accumulate
 */

class WeightedSum {
    // TODO: Add member
    
public:
    // TODO: Constructor
    
    // TODO: operator()(double sum, double value)
};

void testExercise8() {
    cout << "\n=== EXERCISE 8: Binary Functor ===" << endl;
    
    /*
    std::vector<double> values = {1.0, 2.0, 3.0, 4.0, 5.0};
    
    // Normal sum = 15
    double normal = std::accumulate(values.begin(), values.end(), 0.0);
    cout << "  Normal sum: " << normal << endl;
    
    // Weighted sum with weight 0.5 = 7.5
    double weighted = std::accumulate(values.begin(), values.end(), 0.0, 
                                      WeightedSum(0.5));
    cout << "  Weighted sum (0.5): " << weighted << endl;
    assert(weighted == 7.5);
    
    // Weighted sum with weight 2.0 = 30
    weighted = std::accumulate(values.begin(), values.end(), 0.0, 
                               WeightedSum(2.0));
    cout << "  Weighted sum (2.0): " << weighted << endl;
    assert(weighted == 30.0);
    
    cout << "Exercise 8 PASSED!" << endl;
    */
    
    cout << "Uncomment test code after implementation" << endl;
}

// ============================================================================
// EXERCISE 9: Functor Generator
// ============================================================================

/**
 * TODO: Create a functor that generates values in sequence.
 * 
 * Requirements:
 * 1. Store current value and step
 * 2. operator() returns current and increments by step
 * 3. Works with std::generate
 */

class SequenceGenerator {
    // TODO: Add members
    
public:
    // TODO: Constructor(start, step)
    
    // TODO: operator()
};

void testExercise9() {
    cout << "\n=== EXERCISE 9: Functor Generator ===" << endl;
    
    /*
    std::vector<int> seq(10);
    
    // Generate 0, 2, 4, 6, ...
    std::generate(seq.begin(), seq.end(), SequenceGenerator(0, 2));
    
    cout << "  Even numbers: ";
    for (int n : seq) cout << n << " ";
    cout << endl;
    
    assert(seq[0] == 0);
    assert(seq[4] == 8);
    assert(seq[9] == 18);
    
    // Generate 100, 95, 90, ...
    std::generate(seq.begin(), seq.end(), SequenceGenerator(100, -5));
    
    cout << "  Countdown: ";
    for (int n : seq) cout << n << " ";
    cout << endl;
    
    assert(seq[0] == 100);
    assert(seq[9] == 55);
    
    cout << "Exercise 9 PASSED!" << endl;
    */
    
    cout << "Uncomment test code after implementation" << endl;
}

// ============================================================================
// EXERCISE 10: Practical Challenge - Sorting with Multiple Criteria
// ============================================================================

/**
 * TODO: Create functors for sorting students by multiple criteria.
 * 
 * Requirements:
 * 1. Student struct with name, grade, age
 * 2. SortByGrade functor (descending)
 * 3. SortByAge functor (ascending)
 * 4. SortByName functor (alphabetical)
 * 5. CompositeSort that sorts by primary then secondary criteria
 */

struct Student {
    string name;
    double grade;
    int age;
};

// TODO: Implement sorting functors

class SortByGrade {
public:
    // TODO: operator()(const Student& a, const Student& b)
};

class SortByAge {
public:
    // TODO: operator()(const Student& a, const Student& b)
};

class SortByName {
public:
    // TODO: operator()(const Student& a, const Student& b)
};

void testExercise10() {
    cout << "\n=== EXERCISE 10: Multi-Criteria Sort ===" << endl;
    
    /*
    std::vector<Student> students = {
        {"Alice", 85.5, 20},
        {"Bob", 92.0, 21},
        {"Charlie", 85.5, 19},
        {"Diana", 92.0, 22},
        {"Eve", 78.0, 20}
    };
    
    // Sort by grade (descending)
    std::sort(students.begin(), students.end(), SortByGrade());
    cout << "  By grade:" << endl;
    for (const auto& s : students) {
        cout << "    " << s.name << ": " << s.grade << endl;
    }
    
    // Sort by age (ascending)
    std::sort(students.begin(), students.end(), SortByAge());
    cout << "  By age:" << endl;
    for (const auto& s : students) {
        cout << "    " << s.name << ": " << s.age << endl;
    }
    
    cout << "Exercise 10 PASSED!" << endl;
    */
    
    cout << "Uncomment test code after implementation" << endl;
}

// ============================================================================
// MAIN
// ============================================================================

int main() {
    cout << "╔══════════════════════════════════════════════════════════════╗" << endl;
    cout << "║   FRIEND FUNCTIONS, FRIEND CLASSES & FUNCTORS EXERCISES      ║" << endl;
    cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
    
    testExercise1();
    testExercise2();
    testExercise3();
    testExercise4();
    testExercise5();
    testExercise6();
    testExercise7();
    testExercise8();
    testExercise9();
    testExercise10();
    
    cout << "\n═══════════════════════════════════════════════════════════════" << endl;
    cout << "Complete all exercises by implementing the TODO sections!" << endl;
    cout << "Key concepts:" << endl;
    cout << "  - Friend functions break encapsulation selectively" << endl;
    cout << "  - Friend classes get full private access" << endl;
    cout << "  - Functors are objects that behave like functions" << endl;
    cout << "  - Functors can maintain state between calls" << endl;
    cout << "  - Use functors with STL algorithms" << endl;
    
    return 0;
}
Exercises - C++ Tutorial | DeepML