Bỏ qua để đến nội dung

Constructor và Destructor

Constructor (hàm tạo) và destructor (hàm hủy) là hai phương thức đặc biệt của class, tự động được gọi khi một object được tạo ra và khi object đó bị hủy.

Constructor là hàm thành viên cùng tên với class, không có kiểu trả về, tự động chạy ngay khi một object được tạo ra - dùng để khởi tạo giá trị ban đầu cho các thuộc tính.

#include <iostream>
#include <string>
class Dog {
public:
std::string name;
int age;
Dog(std::string n, int a) { // Constructor
name = n;
age = a;
std::cout << "Da tao cho " << name << std::endl;
}
};
int main() {
Dog d1("Mực", 2); // Constructor được gọi tự động
std::cout << d1.name << " - " << d1.age << " tuoi" << std::endl;
return 0;
}

Cách khởi tạo thành viên được khuyến khích trong C++ là dùng initializer list, hiệu quả hơn gán giá trị trong thân hàm (đặc biệt với thành viên là object khác, const, hoặc tham chiếu):

class Dog {
public:
std::string name;
int age;
Dog(std::string n, int a) : name(n), age(a) { // Initializer list
// Thân hàm có thể để trống nếu chỉ cần gán giá trị ban đầu
}
};

Nếu không định nghĩa constructor nào, trình biên dịch tự sinh ra một constructor mặc định không tham số. Nhưng ngay khi bạn tự định nghĩa bất kỳ constructor nào, constructor mặc định do trình biên dịch sinh ra sẽ không còn tồn tại nữa:

class Dog {
public:
std::string name;
Dog() { // Tự viết constructor mặc định (không tham số)
name = "Khong ten";
}
Dog(std::string n) : name(n) {}
};
int main() {
Dog d1; // Gọi constructor không tham số
Dog d2("Mực"); // Gọi constructor có tham số
return 0;
}

Nạp chồng constructor (constructor overloading)

Phần tiêu đề “Nạp chồng constructor (constructor overloading)”

Giống hàm thường, class có thể có nhiều constructor khác nhau về số lượng/kiểu tham số:

class Rectangle {
public:
double width, height;
Rectangle() : width(1), height(1) {} // Không tham số
Rectangle(double side) : width(side), height(side) {} // Hình vuông
Rectangle(double w, double h) : width(w), height(h) {} // Chữ nhật
};
int main() {
Rectangle r1; // 1x1
Rectangle r2(5); // 5x5 (hình vuông)
Rectangle r3(4, 6); // 4x6 (chữ nhật)
return 0;
}

Destructor là hàm thành viên tên là ~TenClass, không có tham số và không có kiểu trả về, tự động được gọi ngay trước khi object bị hủy (ra khỏi scope, hoặc delete nếu tạo bằng new). Thường dùng để giải phóng tài nguyên (bộ nhớ động, file, kết nối…) - đây chính là nền tảng của RAII.

#include <iostream>
class Logger {
public:
Logger() {
std::cout << "Logger duoc tao" << std::endl;
}
~Logger() { // Destructor
std::cout << "Logger bi huy" << std::endl;
}
};
int main() {
std::cout << "Bat dau main" << std::endl;
{
Logger log; // Constructor chạy khi vào scope
std::cout << "Dang su dung logger" << std::endl;
} // Destructor chạy khi log ra khỏi scope
std::cout << "Ket thuc main" << std::endl;
return 0;
}
// Bat dau main
// Logger duoc tao
// Dang su dung logger
// Logger bi huy
// Ket thuc main
  • Constructor tự động chạy khi tạo object, dùng để khởi tạo giá trị ban đầu; nên dùng initializer list (: thanh_vien(gia_tri))
  • Nếu không tự viết constructor nào, trình biên dịch sinh constructor mặc định; nhưng mất ngay khi bạn tự viết bất kỳ constructor nào khác
  • Class có thể nạp chồng nhiều constructor, giống nạp chồng hàm thường
  • Destructor (~TenClass) tự động chạy khi object bị hủy, thường dùng để giải phóng tài nguyên - nền tảng của RAII