[] and () Operator Overload
Part of the Object Oriented Programming section of Coddy's C++ journey — lesson 45 of 104.
The subscript operator ([]) lets your class behave like an array, providing indexed access to elements. The function call operator (()) turns objects into callable entities, known as functors.
Here's a simple array wrapper with the subscript operator:
class IntArray {
int* data;
size_t size;
public:
IntArray(size_t s) : size(s), data(new int[s]()) {}
~IntArray() { delete[] data; }
int& operator[](size_t index) {
return data[index];
}
const int& operator[](size_t index) const {
return data[index];
}
};Notice we provide two versions: one returns a non-const reference (allowing modification), and the const version works with const objects. This lets you write arr[0] = 5; for reading and writing.
The function call operator creates objects that can be "called" like functions:
class Multiplier {
int factor;
public:
Multiplier(int f) : factor(f) {}
int operator()(int value) const {
return value * factor;
}
};
Multiplier triple(3);
int result = triple(10); // Returns 30Functors are powerful because they can maintain state between calls, unlike regular functions. They're commonly used with STL algorithms where you need customizable behavior that remembers configuration values.
Challenge
EasyLet's build a ScoreTracker class that combines both the subscript and function call operators. This class will store scores for players and let you access them by index using [], while also acting as a functor that applies a bonus multiplier to any score you pass to it.
You'll create two files to organize your code:
ScoreTracker.h: Define aScoreTrackerclass that manages an array of player scores and can apply bonuses. Your class should have:- A dynamically allocated
int*array to store scores - A
size_tmember for the number of scores - A
doublemember for the bonus multiplier - A constructor that takes the size and bonus multiplier, initializing all scores to 0
- A destructor that properly cleans up the dynamic memory
- The subscript operator
[](both const and non-const versions) to access scores by index - The function call operator
()that takes anintscore and returns the score multiplied by the bonus multiplier (as anint) - A
getSize()method that returns the number of scores
The non-const subscript operator returns a reference so you can write
tracker[0] = 100;. The const version allows read-only access for const objects. The function call operator should be markedconstsince it doesn't modify the object's state.- A dynamically allocated
main.cpp: Read the following inputs (each on a separate line):- Number of players (size)
- Bonus multiplier (as a double)
- Scores for each player (one per line, as many as the size)
- A test score to apply the bonus to
Create a
ScoreTracker, use the subscript operator to store each player's score, then display all scores. Finally, use the function call operator to calculate the bonus-applied score.Output format:
Player 0: <score> Player 1: <score> ... Bonus applied to <test_score>: <result>
For example, with 3 players, a 1.5 multiplier, scores of 100, 200, 150, and a test score of 80:
Player 0: 100
Player 1: 200
Player 2: 150
Bonus applied to 80: 120Use std::stoi() and std::stod() for input conversion. Don't forget header guards in your header file.
Cheat sheet
The subscript operator [] allows objects to be accessed like arrays. The function call operator () makes objects callable like functions (functors).
Subscript Operator
Provide both const and non-const versions for read/write access:
class IntArray {
int* data;
size_t size;
public:
IntArray(size_t s) : size(s), data(new int[s]()) {}
~IntArray() { delete[] data; }
// Non-const version: allows modification
int& operator[](size_t index) {
return data[index];
}
// Const version: read-only access
const int& operator[](size_t index) const {
return data[index];
}
};Function Call Operator
Creates functors that can maintain state between calls:
class Multiplier {
int factor;
public:
Multiplier(int f) : factor(f) {}
int operator()(int value) const {
return value * factor;
}
};
Multiplier triple(3);
int result = triple(10); // Returns 30Functors are useful with STL algorithms where customizable behavior with stored configuration is needed.
Try it yourself
#include <iostream>
#include <string>
#include "ScoreTracker.h"
using namespace std;
// TODO: Implement ScoreTracker constructor
ScoreTracker::ScoreTracker(size_t size, double multiplier) {
// TODO: Initialize members and allocate dynamic array
// Initialize all scores to 0
}
// TODO: Implement ScoreTracker destructor
ScoreTracker::~ScoreTracker() {
// TODO: Clean up dynamic memory
}
// TODO: Implement non-const subscript operator
// TODO: Implement const subscript operator
// TODO: Implement function call operator
// TODO: Implement getSize method
size_t ScoreTracker::getSize() const {
// TODO: Return the number of scores
}
int main() {
string line;
// Read number of players
getline(cin, line);
size_t numPlayers = stoi(line);
// Read bonus multiplier
getline(cin, line);
double multiplier = stod(line);
// TODO: Create ScoreTracker with numPlayers and multiplier
// TODO: Read scores for each player and store using subscript operator
// TODO: Read test score
// TODO: Display all player scores in format: "Player X: <score>"
// TODO: Display bonus applied result in format: "Bonus applied to <test_score>: <result>"
return 0;
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesC++ Build & CompilationHeader Files & Source FilesNamespaces & ScopeIntroduction to OOP in C++Classes vs ObjectsThe 'this' PointerMethods (Member Functions)Attributes (Data Members)Ctors & Dtors BasicsRecap - Simple Calculator4Class Properties
Instance vs Static MembersGetters and SettersConst Member FunctionsMutable KeywordStatic Methods and VariablesFriend Functions & ClassesRecap - Bank Account Manager7Inheritance
Basic InheritanceInheritance Access LevelsCtor & Dtor Call OrderMethod OverridingVirtual Functions & VTableMultiple InheritanceVirtual InheritanceRecap - Employee Hierarchy2Memory Management
Stack vs Heap MemoryPointers and ReferencesDynamic Memory (new/delete)Smart Pointers in C++RAII in C++Recap - Dynamic Array Manager5Encapsulation
Access Specifiers in C++Access Specifiers In DepthInformation HidingStruct vs ClassNested & Inner ClassesRecap - Student Records System8Polymorphism
Compile vs Runtime PolymorphFunction OverloadingVirtual Functions RevisitedPure Virtual FunctionsAbstract ClassesInterface Design in C++Dynamic Casting & RTTIRecap - Shape Calculator3Constructors & Destructors
Default ConstructorParameterized ConstructorCopy ConstructorMove ConstructorConstructor Init ListsDelegating ConstructorsDestructor Deep DiveRule of Three / Five / ZeroRecap - String Class6Operator Overloading
Intro to Operator OverloadArithmetic Operator OverloadComparison Operator OverloadStream OperatorsAssignment Operator Overload[] and () Operator OverloadType Conversion OperatorsRecap - Matrix Class9Templates
Function TemplatesClass TemplatesTemplate SpecializationVariadic TemplatesSFINAE & Type Traits BasicsRecap - Generic Container