Các hàm hủy ảo rất hữu ích khi bạn có khả năng xóa một thể hiện của lớp dẫn xuất thông qua một con trỏ tới lớp cơ sở:
class Base
{
// some virtual methods
};
class Derived : public Base
{
~Derived()
{
// Do some important cleanup
}
};
Ở đây, bạn sẽ nhận thấy rằng tôi đã không tuyên bố hàm hủy của Base virtual
. Bây giờ, hãy xem đoạn trích sau:
Base *b = new Derived();
// use b
delete b; // Here's the problem!
Vì hàm hủy của Base không phải virtual
và b
là một Base*
trỏ đến một Derived
đối tượng, nên delete b
có hành vi không xác định :
[Trong delete b
], nếu loại tĩnh của đối tượng cần xóa khác với loại động của nó, loại tĩnh sẽ là lớp cơ sở của loại động của đối tượng cần xóa và loại tĩnh sẽ có hàm hủy ảo hoặc hành vi không xác định .
Trong hầu hết các triển khai, lệnh gọi đến hàm hủy sẽ được giải quyết giống như bất kỳ mã không ảo nào, có nghĩa là hàm hủy của lớp cơ sở sẽ được gọi nhưng không phải là một trong các lớp dẫn xuất, dẫn đến rò rỉ tài nguyên.
Tóm lại, luôn luôn tạo ra các hàm hủy của các lớp cơ sở virtual
khi chúng có nghĩa là bị thao túng đa hình.
Nếu bạn muốn ngăn chặn việc xóa một cá thể thông qua một con trỏ lớp cơ sở, bạn có thể làm cho hàm hủy của lớp cơ sở được bảo vệ và không ảo; bằng cách đó, trình biên dịch sẽ không cho phép bạn gọidelete
con trỏ lớp cơ sở.
Bạn có thể tìm hiểu thêm về ảo và trình hủy lớp cơ sở ảo trong bài viết này từ Herb Sutter .