Search…

Virtual Destructor trong C++

04/09/20203 min read
Destructor là phương thức của 1 lớp, tự động được gọi trước khi đối tượng bị thu hồi (thoát khỏi phạm vi, chương trình kết thúc, sử dụng delete).

Phương pháp lập trình hướng đối tượng Object-Oriented Programming có 4 tính chất: Tính trừu tượng hóa, tính đóng gói, tính kế thừa, tính đa hình. Trong đó tính đa hình được thể hiện qua con trỏ và hàm ảo (virtual function) và hàm hủy ảo (Virtual Destructor) là 1 trong số đó.

Destructor

Destructor là phương thức của 1 lớp, tự động được gọi trước khi đối tượng bị thu hồi (thoát khỏi phạm vi, chương trình kết thúc, sử dụng delete).

Phương thức hủy được khai báo có tên trùng với tên lớp và thêm kí tự ~ ở trước tên phương thức và không có giá trị trả về.

~Product()
{
}

Virtual Destructor

Trong một lớp thì Destructor có thể được đánh dấu làm hàm ảo còn Constructor thì không được đánh dấu là hàm ảo.

virtual Product();   // illegal
virtual ~Product();  // legal

Xét một vài ví dụ để làm rõ Virtual Destructor. Giả sử có lớp cha Base và một lớp con Derived được hiện thực như dưới đây.

Trường hợp 1: Phương thức lớp cha không đánh dấu Virtual

Phương thức hủy lớp cha không được đánh dấu là hàm ảo:

class Base
{
public:
	Base() {};
	~Base() { cout << "Destructor Base\n"; };
};


class Derived : public Base
{
public:
	Derived() {};
	~Derived() { cout << "Destructor Derived\n"; }
};

int main() { Base *b = new Derived(); delete b;
return 0; }

Sau khi Build và Debug, chỉ có dòng "Destructor Base" được xuất ra, có nghĩa là chỉ phương thức lớp cha được gọi nhưng phương thức của lớp con không được gọi. Dẫn đến có thể gây nên thiếu sót như không thu hồi bộ nhớ các cấp phát động của lớp cha hoặc các thủ tục cần thực hiện trước khi đối tượng được thu hồi.

Xét tiếp ví dụ dưới đây, tương tự như ví dụ trên nhưng có sửa đổi ở lớp Derived

class Base
{
public:
	Base() {};
	~Base() { cout << "Destructor Base\n"; };
};


class Derived : public Base
{
private:
	int* m_array;
public:
	Derived() { this->m_array = new int[1024]; };
	~Derived()
	{
		cout << "Destructor Derived\n";
		delete this->m_array;
	}
};

int main() { Base *b = new Derived(); delete b; return 0; }

Với lớp con như trên, mặc dù định nghĩa phương thức để giải phóng m_array nhưng phương thức của lớp con không được gọi. Có nghĩa là chương tình đã rò rỉ 1024*4 bytes bộ nhớ.

Trường hợp 2: Phương thức lớp cha có đánh dấu Virtual

Phương thức lớp cha được đánh dấu là phương thức ảo:

class Base
{
public:
	Base() {};
	virtual ~Base() { cout << "Destructor Base\n"; };
};


class Derived : public Base
{
public:
	Derived() {};
	~Derived() { cout << "Destructor Derived\n"; }
};

int main() { Base *b = new Derived(); delete b; return 0; }

Bulid và Debug thì chương trình xuất ra hai dòng là

Destructor Derived
Destructor Base

Như vậy phương thức hủy của lớp con được gọi trước sau đó mới gọi phương thức hủy lớp cha và các thủ tục cần thiết trước khi hủy các đối tượng đã được thực hiện đầy đủ.

IO Stream

IO Stream Co., Ltd

30 Trinh Dinh Thao, Hoa Thanh ward, Tan Phu district, Ho Chi Minh city, Vietnam
+84 28 22 00 11 12
developer@iostream.co

383/1 Quang Trung, ward 10, Go Vap district, Ho Chi Minh city
Business license number: 0311563559 issued by the Department of Planning and Investment of Ho Chi Minh City on February 23, 2012

©IO Stream, 2013 - 2024