Menu
CoddyTech

[] 和 () 运算符重载

本课属于 Coddy C++ 学习旅程的“面向对象编程”单元。第 45 课,共 104 课。

下标运算符([])可以让你的类像数组一样运行,从而通过索引访问元素。函数调用运算符(())可以让对象变成可调用的实体,这种对象称为函数对象。

下面是一个带有下标运算符的简单数组包装器:

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];
    }
};

注意,我们提供了两个版本:一个返回非 const 引用(允许修改),const 版本则适用于 const 对象。这样你就可以使用 arr[0] = 5; 进行读取和写入。

函数调用运算符可以创建像函数一样被“调用”的对象:

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);    // 返回 30

函子很强大,因为它们可以在多次调用之间保持状态,这一点与普通函数不同。它们常用于 STL 算法中,适合需要记住配置值的可定制行为。

challenge icon

挑战

简单

我们来创建一个 ScoreTracker 类,将下标运算符和函数调用运算符结合起来。这个类会存储玩家的分数,让你可以使用 [] 按索引访问分数,同时它也会充当一个函数对象,对传入的分数应用奖励倍数。

你需要创建两个文件来组织代码:

  • ScoreTracker.h:定义一个 ScoreTracker 类,用于管理玩家分数数组并应用奖励。你的类应包含:
    • 一个动态分配的 int* 数组,用于存储分数
    • 一个 size_t 成员,用于记录分数的数量
    • 一个 double 成员,用于记录奖励倍数
    • 一个接收大小和奖励倍数的构造函数,并将所有分数初始化为 0
    • 一个能正确清理动态内存的析构函数
    • 下标运算符 [](包括 const 和非 const 版本),用于按索引访问分数
    • 函数调用运算符 (),接收一个 int 类型的分数,并返回该分数乘以奖励倍数后的结果(类型为 int)
    • 一个 getSize() 方法,用于返回分数的数量

    非 const 下标运算符会返回引用,因此你可以这样写:tracker[0] = 100;。const 版本允许对 const 对象进行只读访问。函数调用运算符应标记为 const,因为它不会修改对象的状态。

  • main.cpp:读取以下输入(每项各占一行):
    1. 玩家数量(大小)
    2. 奖励倍数(类型为 double)
    3. 每位玩家的分数(每行一个,数量与玩家数量相同)
    4. 一个用于应用奖励的测试分数

    创建一个 ScoreTracker,使用下标运算符存储每位玩家的分数,然后显示所有分数。最后,使用函数调用运算符计算应用奖励后的分数。

    输出格式:

    Player 0: <score>
    Player 1: <score>
    ...
    Bonus applied to <test_score>: <result>

例如,玩家数量为 3,奖励倍数为 1.5,分数分别为 100、200、150,测试分数为 80:

Player 0: 100
Player 1: 200
Player 2: 150
Bonus applied to 80: 120

使用 std::stoi() 和 std::stod() 转换输入。别忘了在头文件中添加头文件保护。

亲手试试

#include <iostream>
#include <string>
#include "ScoreTracker.h"

using namespace std;

// TODO: 实现 ScoreTracker 构造函数
ScoreTracker::ScoreTracker(size_t size, double multiplier) {
    // TODO: 初始化成员并分配动态数组
    // 将所有分数初始化为 0
}

// TODO: 实现 ScoreTracker 析构函数
ScoreTracker::~ScoreTracker() {
    // TODO: 释放动态内存
}

// TODO: 实现非 const 下标运算符

// TODO: 实现 const 下标运算符

// TODO: 实现函数调用运算符

// TODO: 实现 getSize 方法
size_t ScoreTracker::getSize() const {
    // TODO: 返回分数的数量
}

int main() {
    string line;
    
    // 读取玩家数量
    getline(cin, line);
    size_t numPlayers = stoi(line);
    
    // 读取奖励倍数
    getline(cin, line);
    double multiplier = stod(line);
    
    // TODO: 使用 numPlayers 和 multiplier 创建 ScoreTracker
    
    // TODO: 读取每位玩家的分数,并用下标运算符存储
    
    // TODO: 读取测试分数
    
    // TODO: 按以下格式显示所有玩家的分数:"Player X: <score>"
    
    // TODO: 按以下格式显示应用奖励后的结果:"Bonus applied to <test_score>: <result>"
    
    return 0;
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: C++ 在线编译器