Menu
CoddyTech

Hàm khởi tạo ủy quyền

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

Khi có nhiều hàm khởi tạo dùng chung logic khởi tạo, bạn có thể dùng hàm khởi tạo ủy quyền để tránh lặp code. Hàm khởi tạo ủy quyền gọi một hàm khởi tạo khác của cùng lớp trong danh sách khởi tạo.

class Player {
    std::string name;
    int health;
    int level;
public:
    // Hàm khởi tạo chính (constructor): thực hiện công việc chính
    Player(std::string n, int h, int lvl) 
        : name(n), health(h), level(lvl) {}
    
    // Ủy quyền cho hàm khởi tạo chính
    Player(std::string n) : Player(n, 100, 1) {}
    
    // Hàm khởi tạo mặc định cũng ủy quyền
    Player() : Player("Unknown") {}
};

Việc ủy quyền diễn ra trong danh sách khởi tạo bằng cách dùng tên lớp theo sau là các đối số. Khi gọi Player(), nó ủy quyền cho Player(std::string), rồi hàm này ủy quyền cho hàm khởi tạo có ba tham số. Chuỗi ủy quyền chạy từ hàm khởi tạo đích ngược về hàm khởi tạo ban đầu.

Có một quy tắc quan trọng: hàm khởi tạo ủy quyền không thể có thành viên nào khác trong danh sách khởi tạo. Việc ủy quyền phải là mục duy nhất:

class Item {
    int id;
    int value;
public:
    Item(int i, int v) : id(i), value(v) {}
    
    // Lỗi! Không thể vừa ủy quyền khởi tạo vừa khởi tạo thành viên
    // Item(int i) : Item(i, 0), id(i) {}
    
    // Đúng: chỉ ủy quyền khởi tạo
    Item(int i) : Item(i, 0) {}
};

Các hàm khởi tạo ủy quyền giúp tập trung logic khởi tạo vào một nơi, nhờ đó bạn dễ bảo trì code hơn và giảm nguy cơ mắc lỗi do lặp code.

challenge icon

Thử thách

Dễ

Hãy xây dựng một hệ thống cài đặt kết nối để minh họa cách các hàm khởi tạo ủy quyền có thể loại bỏ code trùng lặp bằng cách nối các lệnh gọi hàm khởi tạo với nhau.

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

  • Connection.h: Định nghĩa lớp Connection đại diện cho một kết nối mạng với nhiều tùy chọn cấu hình. Lớp của bạn cần có:
    • Các thành viên riêng tư: host (chuỗi), port (int), timeout (int tính bằng giây) và secure (bool)
    • Một hàm khởi tạo chính nhận cả bốn tham số và khởi tạo tất cả thành viên bằng danh sách khởi tạo. Hàm khởi tạo này cần in ra "Connection configured: <host>:<port>"
    • Một hàm khởi tạo chỉ nhận host và port, ủy quyền cho hàm khởi tạo chính, với giá trị mặc định của timeout là 30 và giá trị mặc định của secure là false
    • Một hàm khởi tạo chỉ nhận host, ủy quyền cho hàm khởi tạo hai tham số, với giá trị mặc định của port là 80
    • Một hàm khởi tạo mặc định, ủy quyền cho hàm khởi tạo một tham số, với giá trị mặc định của host là "localhost"
    • Một phương thức getInfo() trả về chuỗi theo định dạng: "<host>:<port> (timeout: <timeout>s, secure: <yes/no>)"
  • main.cpp: Minh họa chuỗi ủy quyền bằng cách tạo các kết nối với những hàm khởi tạo khác nhau. Đọc tên máy chủ và số cổng từ đầu vào, mỗi giá trị trên một dòng riêng, sau đó:
    • Tạo một Connection bằng hàm khởi tạo mặc định
    • Tạo một Connection chỉ bằng tên máy chủ từ đầu vào
    • Tạo một Connection bằng cả tên máy chủ và số cổng từ đầu vào
    • Tạo một Connection với tên máy chủ và số cổng từ đầu vào, giá trị timeout là 60 và secure được đặt thành true
    • In ra getInfo() cho từng kết nối, mỗi kết quả trên một dòng

Chuỗi ủy quyền diễn ra như sau: hàm khởi tạo mặc định gọi hàm khởi tạo một tham số, hàm này gọi hàm khởi tạo hai tham số, rồi hàm này gọi hàm khởi tạo chính có bốn tham số. Điều này có nghĩa là thông báo "Connection configured" được in ra một lần cho mỗi đối tượng được tạo, luôn từ hàm khởi tạo chính.

Đối với trạng thái bảo mật trong getInfo(), hãy in ra "yes" nếu secure là true, nếu không thì in ra "no".

Thêm tệp tiêu đề vào main.cpp bằng #include "Connection.h".

Tự làm thử

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

using namespace std;

int main() {
    // Đọc đầu vào
    string host;
    int port;
    cin >> host;
    cin >> port;

    // TODO: Tạo một Connection bằng hàm khởi tạo mặc định

    // TODO: Tạo một Connection chỉ với host từ đầu vào

    // TODO: Tạo một Connection với cả host và port từ đầu vào

    // TODO: Tạo một Connection với host và port từ đầu vào, timeout=60, secure=true

    // TODO: In ra getInfo() cho từng kết nối, mỗi kết nối một dòng

    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