Skip to content

Hàm Khởi tạo và Hủy (Constructors & Destructors)

📖 Giới thiệu

Hàm khởi tạo (Constructor) được gọi tự động khi tạo đối tượng. Hàm hủy (Destructor) được gọi khi đối tượng bị xóa. Chúng giúp quản lý tài nguyên và khởi tạo dữ liệu một cách an toàn.

Ví dụ đơn giản đầu tiên

cpp
#include <iostream>
#include <string>
using namespace std;

class NguoiDung {
private:
    string ten;
    int tuoi;
    
public:
    // Constructor - tự động chạy khi tạo đối tượng
    NguoiDung() {
        ten = "Chưa có tên";
        tuoi = 0;
        cout << "Đã tạo người dùng mới!" << endl;
    }
    
    // Destructor - tự động chạy khi xóa đối tượng
    ~NguoiDung() {
        cout << "Đã xóa người dùng: " << ten << endl;
    }
    
    void dat_thong_tin(string t, int tuoi_moi) {
        ten = t;
        tuoi = tuoi_moi;
    }
    
    void hien_thi() {
        cout << "Tên: " << ten << ", Tuổi: " << tuoi << endl;
    }
};

int main() {
    NguoiDung user1;  // Constructor được gọi
    user1.dat_thong_tin("Minh", 20);
    user1.hien_thi();
    
    return 0;  // Destructor được gọi khi kết thúc
}

🔧 Cú pháp

Constructor cơ bản

cpp
class TenLop {
public:
    // Default constructor
    TenLop() {
        // Khởi tạo mặc định
    }
    
    // Parameterized constructor  
    TenLop(tham_so_1, tham_so_2) {
        // Khởi tạo với tham số
    }
    
    // Copy constructor
    TenLop(const TenLop& other) {
        // Sao chép từ đối tượng khác
    }
};

Destructor

cpp
class TenLop {
public:
    ~TenLop() {
        // Dọn dẹp tài nguyên
    }
};

Member Initializer List

cpp
class TenLop {
private:
    int x, y;
    string ten;
    
public:
    // Cách hiệu quả hơn
    TenLop(int a, int b, string t) : x(a), y(b), ten(t) {
        // Constructor body
    }
};

🔬 Phân tích & Giải thích

Các loại Constructor

1. Default Constructor: Không có tham số

cpp
class DienThoai {
private:
    string hang;
    int gia;
    
public:
    DienThoai() {
        hang = "Không xác định";
        gia = 0;
        cout << "Tạo điện thoại mặc định" << endl;
    }
};

2. Parameterized Constructor: Có tham số

cpp
class DienThoai {
private:
    string hang;
    int gia;
    
public:
    DienThoai(string h, int g) {
        hang = h;
        gia = g;
        cout << "Tạo điện thoại " << hang << endl;
    }
};

3. Copy Constructor: Sao chép đối tượng

cpp
class DienThoai {
private:
    string hang;
    int gia;
    
public:
    DienThoai(const DienThoai& other) {
        hang = other.hang;
        gia = other.gia;
        cout << "Sao chép điện thoại " << hang << endl;
    }
};

💻 Ví dụ minh họa

Ví dụ 1: Quản lý Sinh viên

cpp
#include <iostream>
#include <string>
using namespace std;

class SinhVien {
private:
    string ten;
    int tuoi;
    float diem;
    
public:
    // Default constructor
    SinhVien() {
        ten = "Chưa có tên";
        tuoi = 18;
        diem = 0.0;
        cout << "Tạo sinh viên mặc định" << endl;
    }
    
    // Constructor với tham số
    SinhVien(string t, int tuoi_moi, float d = 0.0) {
        ten = t;
        tuoi = tuoi_moi;
        diem = d;
        cout << "Tạo sinh viên: " << ten << endl;
    }
    
    // Copy constructor
    SinhVien(const SinhVien& other) {
        ten = other.ten + " (Copy)";
        tuoi = other.tuoi;
        diem = other.diem;
        cout << "Sao chép sinh viên: " << ten << endl;
    }
    
    // Destructor
    ~SinhVien() {
        cout << "Xóa sinh viên: " << ten << endl;
    }
    
    void hien_thong_tin() {
        cout << "Tên: " << ten << ", Tuổi: " << tuoi << ", Điểm: " << diem << endl;
    }
    
    void cap_nhat_diem(float diem_moi) {
        diem = diem_moi;
        cout << ten << " có điểm mới: " << diem << endl;
    }
};

int main() {
    cout << "=== Tạo sinh viên ===" << endl;
    
    // Sử dụng các constructor khác nhau
    SinhVien sv1;                           // Default constructor
    SinhVien sv2("Minh", 20);              // Constructor với tham số
    SinhVien sv3("Hoa", 19, 8.5);          // Constructor đầy đủ tham số
    SinhVien sv4 = sv2;                     // Copy constructor
    
    cout << "\n=== Thông tin sinh viên ===" << endl;
    sv1.hien_thong_tin();
    sv2.hien_thong_tin();
    sv3.hien_thong_tin();
    sv4.hien_thong_tin();
    
    cout << "\n=== Cập nhật điểm ===" << endl;
    sv1.cap_nhat_diem(7.0);
    sv2.cap_nhat_diem(8.0);
    
    cout << "\n=== Kết thúc chương trình ===" << endl;
    return 0; // Destructors được gọi tự động
}

Ví dụ 2: Quản lý Ngân hàng với bảo mật

cpp
#include <iostream>
#include <string>
using namespace std;

class TaiKhoan {
private:
    string soTK;
    string chuTK;
    double soDu;
    static int soLuongTK; // Đếm số tài khoản
    
public:
    // Constructor mặc định
    TaiKhoan() {
        soTK = "TK" + to_string(++soLuongTK);
        chuTK = "Khách hàng " + to_string(soLuongTK);
        soDu = 0.0;
        cout << "Tạo tài khoản mặc định: " << soTK << endl;
    }
    
    // Constructor với tham số
    TaiKhoan(string ten, double du_dau = 50000) {
        soTK = "TK" + to_string(++soLuongTK);
        chuTK = ten;
        soDu = (du_dau >= 50000) ? du_dau : 50000; // Số dư tối thiểu
        cout << "Tạo tài khoản cho: " << chuTK << " (Số TK: " << soTK << ")" << endl;
    }
    
    // Copy constructor (để chuyển tài khoản)
    TaiKhoan(const TaiKhoan& other) {
        soTK = "TK" + to_string(++soLuongTK);
        chuTK = other.chuTK + " (Chuyển đổi)";
        soDu = other.soDu;
        cout << "Chuyển đổi tài khoản: " << chuTK << endl;
    }
    
    // Destructor
    ~TaiKhoan() {
        cout << "Đóng tài khoản: " << soTK << " (" << chuTK << ")" << endl;
        soLuongTK--;
    }
    
    void hien_thong_tin() {
        cout << "Số TK: " << soTK << " | Chủ TK: " << chuTK 
             << " | Số dư: " << soDu << " VND" << endl;
    }
    
    void gui_tien(double tien) {
        if (tien > 0) {
            soDu += tien;
            cout << "Gửi " << tien << " VND thành công!" << endl;
        }
    }
    
    bool rut_tien(double tien) {
        if (tien > 0 && soDu >= tien + 50000) { // Giữ lại tối thiểu 50k
            soDu -= tien;
            cout << "Rút " << tien << " VND thành công!" << endl;
            return true;
        }
        cout << "Không thể rút tiền!" << endl;
        return false;
    }
    
    static int lay_so_luong_tai_khoan() {
        return soLuongTK;
    }
};

// Khởi tạo biến static
int TaiKhoan::soLuongTK = 0;

int main() {
    cout << "=== HỆ THỐNG NGÂN HÀNG ===" << endl;
    
    // Tạo các tài khoản
    TaiKhoan tk1;                              // Mặc định
    TaiKhoan tk2("Nguyễn Văn A", 1000000);     // Với tham số
    TaiKhoan tk3("Trần Thị B");                // Số dư mặc định
    
    cout << "\nSố lượng tài khoản hiện tại: " << TaiKhoan::lay_so_luong_tai_khoan() << endl;
    
    cout << "\n=== THÔNG TIN TÀI KHOẢN ===" << endl;
    tk1.hien_thong_tin();
    tk2.hien_thong_tin();
    tk3.hien_thong_tin();
    
    cout << "\n=== GIAO DỊCH ===" << endl;
    tk1.gui_tien(500000);
    tk1.hien_thong_tin();
    
    tk2.rut_tien(200000);
    tk2.hien_thong_tin();
    
    // Tạo tài khoản chuyển đổi
    cout << "\n=== CHUYỂN ĐỔI TÀI KHOẢN ===" << endl;
    TaiKhoan tk4 = tk2; // Copy constructor
    tk4.hien_thong_tin();
    
    cout << "\n=== KẾT THÚC ===" << endl;
    return 0;
}

Ví dụ 3: Game với quản lý tài nguyên

cpp
#include <iostream>
#include <string>
using namespace std;

class Weapon {
private:
    string* ten;      // Con trỏ để demo quản lý bộ nhớ
    int damage;
    int độBền;
    
public:
    // Constructor mặc định
    Weapon() {
        ten = new string("Tay không");
        damage = 5;
        độBền = 100;
        cout << "Tạo vũ khí: " << *ten << endl;
    }
    
    // Constructor với tham số
    Weapon(string tenVK, int dmg, int durability = 100) {
        ten = new string(tenVK);
        damage = dmg;
        độBền = durability;
        cout << "Tạo vũ khí: " << *ten << " (Damage: " << damage << ")" << endl;
    }
    
    // Copy constructor (quan trọng với con trỏ!)
    Weapon(const Weapon& other) {
        ten = new string(*other.ten + " (Copy)");
        damage = other.damage;
        độBền = other.độBền;
        cout << "Sao chép vũ khí: " << *ten << endl;
    }
    
    // Destructor (giải phóng bộ nhớ)
    ~Weapon() {
        cout << "Hủy vũ khí: " << *ten << endl;
        delete ten; // Quan trọng: giải phóng bộ nhớ
    }
    
    void attack() {
        if (độBền > 0) {
            cout << "Tấn công với " << *ten << " - Damage: " << damage << endl;
            độBền -= 10;
            if (độBền <= 0) {
                cout << *ten << " đã bị hỏng!" << endl;
            }
        } else {
            cout << *ten << " đã hỏng, không thể tấn công!" << endl;
        }
    }
    
    void hien_thong_tin() {
        cout << "Vũ khí: " << *ten << " | Damage: " << damage 
             << " | Độ bền: " << độBền << "%" << endl;
    }
    
    void sua_chua() {
        độBền = 100;
        cout << "Đã sửa chữa " << *ten << "!" << endl;
    }
};

class NhanVat {
private:
    string ten;
    int hp;
    Weapon* vuKhi; // Con trỏ đến vũ khí
    
public:
    // Constructor
    NhanVat(string tenNV, int health = 100) {
        ten = tenNV;
        hp = health;
        vuKhi = new Weapon(); // Tạo vũ khí mặc định
        cout << "Tạo nhân vật: " << ten << " (HP: " << hp << ")" << endl;
    }
    
    // Destructor
    ~NhanVat() {
        cout << "Nhân vật " << ten << " rời game!" << endl;
        delete vuKhi; // Xóa vũ khí
    }
    
    void trang_bi_vu_khi(string tenVK, int damage) {
        delete vuKhi; // Xóa vũ khí cũ
        vuKhi = new Weapon(tenVK, damage);
        cout << ten << " trang bị " << tenVK << "!" << endl;
    }
    
    void tan_cong() {
        cout << ten << " tấn công: ";
        vuKhi->attack();
    }
    
    void hien_thong_tin() {
        cout << "\n=== " << ten << " ===" << endl;
        cout << "HP: " << hp << endl;
        vuKhi->hien_thong_tin();
        cout << "=================" << endl;
    }
    
    void sua_vu_khi() {
        vuKhi->sua_chua();
    }
};

int main() {
    cout << "=== GAME RPG ===" << endl;
    
    // Tạo nhân vật
    NhanVat hero("Chiến Binh", 150);
    hero.hien_thong_tin();
    
    cout << "\n=== CHIẾN ĐẤU ===" << endl;
    hero.tan_cong();
    hero.tan_cong();
    
    cout << "\n=== NÂNG CẤP VŨ KHÍ ===" << endl;
    hero.trang_bi_vu_khi("Kiếm Thần", 50);
    hero.hien_thong_tin();
    
    hero.tan_cong();
    hero.tan_cong();
    
    cout << "\n=== SỬA CHỮA ===" << endl;
    hero.sua_vu_khi();
    hero.hien_thong_tin();
    
    cout << "\n=== KẾT THÚC GAME ===" << endl;
    return 0;
}

🏋️ Thực hành

Bài tập 1: Lớp Xe hơi

Tạo lớp XeHoi với:

  • Constructor mặc định và có tham số
  • Constructor copy
  • Destructor
  • Phương thức khởi động, dừng xe

Bài tập 2: Quản lý Sách

Tạo lớp Sach với constructor để:

  • Khởi tạo tên sách, tác giả, giá
  • Sao chép sách (tăng số lượng bản copy)
  • Destructor hiển thị thông báo

Bài tập 3: Mảng động

Tạo lớp MangDong với:

  • Constructor cấp phát bộ nhớ
  • Copy constructor (deep copy)
  • Destructor giải phóng bộ nhớ

📋 Tóm tắt

  1. Constructor: Khởi tạo đối tượng tự động

    • Default constructor: không tham số
    • Parameterized constructor: có tham số
    • Copy constructor: sao chép đối tượng
  2. Destructor: Dọn dẹp khi đối tượng bị xóa

    • Tên: ~TenLop()
    • Không có tham số, không có giá trị trả về
  3. Member Initializer List: Khởi tạo hiệu quả hơn

  4. Quản lý bộ nhớ: Quan trọng với con trỏ

Bài tiếp theo: Đóng gói - Tìm hiểu về che giấu thông tin và bảo mật dữ liệu.

Khóa học C++ miễn phí