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
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
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ề
- Tên:
Member Initializer List: Khởi tạo hiệu quả hơn
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.