cpp
exercises
exercises.cpp⚙️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;
}