Menu
CoddyTech

Nạp chồng toán tử [] và ()

Thuộc phần Lập trình hướng đối tượng trong hành trình C++ của Coddy. Bài học 45 trên 104.

Toán tử chỉ số dưới ([]) cho phép lớp của bạn hoạt động như một mảng, giúp truy cập các phần tử theo chỉ số. Toán tử gọi hàm (()) biến đối tượng thành thực thể có thể gọi, được gọi là functor.

Đây là một lớp bọc mảng đơn giản có toán tử chỉ số:

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

Lưu ý rằng chúng ta cung cấp hai phiên bản: một phiên bản trả về tham chiếu không hằng số (cho phép chỉnh sửa), còn phiên bản hằng số hoạt động với các đối tượng hằng số. Nhờ vậy, bạn có thể viết arr[0] = 5; để đọc và ghi.

Toán tử gọi hàm tạo ra các đối tượng có thể được “gọi” như hàm:

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);    // Trả về 30

Functor rất mạnh vì chúng có thể duy trì trạng thái giữa các lần gọi, không giống như các hàm thông thường. Chúng thường được dùng với các thuật toán STL khi bạn cần hành vi có thể tùy chỉnh và ghi nhớ các giá trị cấu hình.

challenge icon

Thử thách

Dễ

Hãy tạo một lớp ScoreTracker kết hợp cả toán tử chỉ số và toán tử gọi hàm. Lớp này lưu điểm của người chơi và cho phép bạn truy cập điểm theo chỉ số bằng [], đồng thời hoạt động như một đối tượng hàm áp dụng hệ số nhân tiền thưởng cho bất kỳ điểm nào bạn truyền vào.

Bạn sẽ tạo hai tệp để sắp xếp code:

  • ScoreTracker.h: Định nghĩa lớp ScoreTracker để quản lý mảng điểm của người chơi và áp dụng tiền thưởng. Lớp của bạn cần có:
    • Mảng int* được cấp phát động để lưu điểm
    • Một thành viên size_t biểu thị số lượng điểm
    • Một thành viên double biểu thị hệ số nhân tiền thưởng
    • Một hàm khởi tạo nhận kích thước và hệ số nhân tiền thưởng, đồng thời khởi tạo tất cả điểm bằng 0
    • Một hàm hủy dọn dẹp bộ nhớ động đúng cách
    • Toán tử chỉ số [] (cả phiên bản const và không const) để truy cập điểm theo chỉ số
    • Toán tử gọi hàm () nhận một điểm int và trả về điểm nhân với hệ số nhân tiền thưởng (dưới dạng int)
    • Một phương thức getSize() trả về số lượng điểm

    Toán tử chỉ số không const trả về một tham chiếu để bạn có thể viết tracker[0] = 100;. Phiên bản const cho phép chỉ đọc các đối tượng const. Toán tử gọi hàm cần được đánh dấu const vì nó không thay đổi trạng thái của đối tượng.

  • main.cpp: Đọc các đầu vào sau (mỗi đầu vào trên một dòng riêng):
    1. Số người chơi (kích thước)
    2. Hệ số nhân tiền thưởng (dưới dạng double)
    3. Điểm của từng người chơi (mỗi dòng một điểm, số dòng bằng kích thước)
    4. Một điểm kiểm tra để áp dụng tiền thưởng

    Tạo một ScoreTracker, dùng toán tử chỉ số để lưu điểm của từng người chơi, sau đó hiển thị tất cả điểm. Cuối cùng, dùng toán tử gọi hàm để tính điểm sau khi áp dụng tiền thưởng.

    Định dạng đầu ra:

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

Ví dụ, với 3 người chơi, hệ số nhân 1.5, điểm lần lượt là 100, 200, 150 và điểm kiểm tra là 80:

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

Dùng std::stoi() và std::stod() để chuyển đổi đầu vào. Đừng quên các header guard trong tệp header.

Tự làm thử

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

using namespace std;

// TODO: Triển khai hàm khởi tạo ScoreTracker
ScoreTracker::ScoreTracker(size_t size, double multiplier) {
    // TODO: Khởi tạo các thành viên và cấp phát mảng động
    // Khởi tạo tất cả điểm số bằng 0
}

// TODO: Triển khai hàm hủy ScoreTracker
ScoreTracker::~ScoreTracker() {
    // TODO: Giải phóng bộ nhớ động
}

// TODO: Triển khai toán tử truy cập bằng chỉ số không const

// TODO: Triển khai toán tử truy cập bằng chỉ số const

// TODO: Triển khai toán tử gọi hàm

// TODO: Triển khai phương thức getSize
size_t ScoreTracker::getSize() const {
    // TODO: Trả về số lượng điểm số
}

int main() {
    string line;
    
    // Đọc số lượng người chơi
    getline(cin, line);
    size_t numPlayers = stoi(line);
    
    // Đọc hệ số nhân điểm thưởng
    getline(cin, line);
    double multiplier = stod(line);
    
    // TODO: Tạo ScoreTracker với numPlayers và multiplier
    
    // TODO: Đọc điểm của từng người chơi và lưu bằng toán tử chỉ số
    
    // TODO: Đọc điểm kiểm tra
    
    // TODO: Hiển thị điểm của tất cả người chơi theo định dạng: "Player X: <score>"
    
    // TODO: Hiển thị kết quả sau khi áp dụng hệ số thưởng theo định dạng: "Bonus applied to <test_score>: <result>"
    
    return 0;
}
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch C++ online