Menu
CoddyTech

Hàm truy xuất và hàm thiết lập

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 28 trên 104.

Khi các thành viên của lớp ở chế độ riêng tư, code bên ngoài không thể truy cập trực tiếp vào chúng. Hàm getter và hàm setter là các phương thức công khai giúp kiểm soát quyền truy cập vào những thành viên riêng tư này. Hàm getter lấy giá trị, còn hàm setter thay đổi chúng.

class Temperature {
    double celsius;    // Riêng tư: không thể truy cập trực tiếp
    
public:
    // Phương thức getter: trả về giá trị
    double getCelsius() const {
        return celsius;
    }
    
    // Phương thức setter: kiểm tra rồi thay đổi giá trị
    void setCelsius(double value) {
        if (value >= -273.15) {    // Kiểm tra độ không tuyệt đối
            celsius = value;
        }
    }
};

Sức mạnh thực sự của các hàm setter nằm ở khả năng kiểm tra tính hợp lệ.

Thay vì cho phép gán bất kỳ giá trị nào, bạn có thể đặt ra các quy tắc. Trong ví dụ trên, các nhiệt độ thấp hơn độ không tuyệt đối sẽ bị từ chối. Nếu không có phương thức setter, bất kỳ ai cũng có thể trực tiếp gán dữ liệu không hợp lệ.

Getter cũng có thể biến đổi dữ liệu trước khi trả về:

class Temperature {
    double celsius;
public:
    double getCelsius() const { return celsius; }
    
    // Phương thức getter tính toán: không lưu giá trị fahrenheit mà tính ra khi cần
    double getFahrenheit() const {
        return celsius * 9.0 / 5.0 + 32.0;
    }
    
    void setCelsius(double value) { celsius = value; }
};

Hãy chú ý đến từ khóa const trong các hàm getter, từ khóa này cho biết chúng không sửa đổi đối tượng. Các hàm setter không thể là const vì mục đích của chúng là thay đổi giá trị thành viên. Cách dùng hàm getter và setter này là nền tảng của tính đóng gói, giúp bạn kiểm soát hoàn toàn cách dữ liệu trong lớp được truy cập và sửa đổi.

challenge icon

Thử thách

Dễ

Hãy xây dựng hệ thống hồ sơ người chơi để minh họa cách các hàm truy cập và hàm thiết lập cung cấp quyền truy cập có kiểm soát vào dữ liệu riêng tư, bao gồm xác thực và thuộc tính được tính toán.

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

  • Player.h: Định nghĩa lớp Player để quản lý hồ sơ nhân vật trong trò chơi với quyền truy cập dữ liệu được bảo vệ. Lớp của bạn cần có:
    • Các thành viên riêng tư: name (chuỗi), level (int) và experience (int)
    • Một hàm khởi tạo nhận tên và khởi tạo level thành 1 và experience thành 0
    • Hàm truy cập getName() trả về tên người chơi
    • Hàm truy cập getLevel() trả về cấp độ hiện tại
    • Hàm truy cập getExperience() trả về số điểm kinh nghiệm hiện tại
    • Hàm thiết lập setName() chỉ chấp nhận tên có ít nhất 3 ký tự. Nếu tên không hợp lệ, hãy giữ nguyên tên hiện tại
    • Hàm thiết lập addExperience(int points) chỉ chấp nhận giá trị dương. Khi kinh nghiệm đạt hoặc vượt 100, người chơi lên cấp: tăng cấp độ thêm 1 và trừ 100 khỏi kinh nghiệm. Việc này có thể xảy ra nhiều lần nếu cộng đủ kinh nghiệm.
    • Hàm truy cập được tính toán getExperienceToNextLevel() trả về số điểm kinh nghiệm cần thêm để đạt cấp độ tiếp theo (luôn bằng 100 - current experience)

    Đánh dấu tất cả các hàm truy cập là const vì chúng không sửa đổi đối tượng.

  • main.cpp: Minh họa cách các hàm truy cập và hàm thiết lập hoạt động. Đọc tên người chơi và số điểm kinh nghiệm cần cộng từ đầu vào (mỗi giá trị trên một dòng riêng), sau đó:
    • Tạo một Player với tên nhập vào
    • In ra "Player: <name>, Level: <level>, XP: <experience>"
    • Cộng số điểm kinh nghiệm đã nhập bằng addExperience()
    • In lại cùng dòng trạng thái để hiển thị trạng thái đã cập nhật
    • In ra "XP to next level: <amount>"
    • Thử đổi tên thành "Al" (sẽ không vượt qua bước xác thực)
    • In ra "Name after invalid change: <name>"
    • Đổi tên thành "Champion" (sẽ thành công)
    • In ra "Name after valid change: <name>"

Đầu vào kinh nghiệm sẽ được cung cấp dưới dạng chuỗi mà bạn cần chuyển đổi thành số nguyên. Thêm tệp tiêu đề vào main.cpp bằng #include "Player.h".

Tự làm thử

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

using namespace std;

int main() {
    // Đọc tên người chơi
    string playerName;
    getline(cin, playerName);

    // Đọc số điểm kinh nghiệm cần cộng (dưới dạng chuỗi, rồi chuyển thành int)
    string expString;
    getline(cin, expString);
    int expToAdd = stoi(expString);

    // TODO: Tạo một Player với tên đầu vào

    // TODO: In ra trạng thái ban đầu: "Player: <name>, Level: <level>, XP: <experience>"

    // TODO: Cộng số điểm kinh nghiệm đầu vào bằng addExperience()

    // TODO: In ra dòng trạng thái đã cập nhật

    // TODO: In ra "XP to next level: <amount>"

    // TODO: Thử đổi tên thành "Al" (bước kiểm tra tính hợp lệ sẽ không chấp nhận)

    // TODO: In ra "Name after invalid change: <name>"

    // TODO: Đổi tên thành "Champion" (bước kiểm tra tính hợp lệ sẽ chấp nhận)

    // TODO: In ra "Name after valid change: <name>"

    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