Trình hủy ảo trong C++

Trinh Huy Ao Trong C



C++ là ngôn ngữ được sử dụng để tạo nền tảng cho khái niệm cơ bản về lập trình và làm cho tư duy logic của lập trình viên trở nên mạnh mẽ. Trong C ++, OOP đóng một vai trò quan trọng vì OOP là ngôn ngữ Hướng đối tượng tạo ra các đối tượng của các lớp. Trong OOP, chúng tôi nghiên cứu các lớp và đối tượng. Các lớp chứa các thành viên dữ liệu là các biến có kiểu khác nhau và các hàm thành viên khác nhau. Với sự trợ giúp của các thể hiện, chúng tôi truy cập dữ liệu của bất kỳ lớp nào. Mỗi lớp có hàm tạo và hàm hủy của nó khi bạn tạo lớp. Hàm tạo được gọi chính nó khi đối tượng của lớp đó được tạo. Chúng ta cũng có thể khởi tạo các biến của một lớp bên trong hàm tạo. Hàm hủy cũng được tạo tự động với hàm tạo nhưng hàm hủy phá hủy đối tượng và đó là hàm cuối cùng được gọi trước khi hủy đối tượng. Tên của lớp, ví dụ lớp “Nghề nghiệp”, được tạo. Hàm tạo của nó là Profession() và hàm hủy là ~Profession(). Ba người họ có cùng tên.

Sau khi nói về OOP, hàm tạo và hàm hủy, bây giờ chúng ta hãy nói về hàm hủy ảo. Các hàm hủy ảo, như tên chỉ định, sẽ hủy đối tượng. Chúng ta có một lớp cơ sở và một lớp dẫn xuất được dẫn xuất từ ​​lớp cơ sở. Cả hai lớp đều có hàm tạo và hàm hủy của chúng. Hàm hủy ảo giải phóng bộ nhớ được phân bổ thông qua đối tượng lớp dẫn xuất trong khi xóa các đối tượng của lớp dẫn xuất bằng cách sử dụng một con trỏ lớp cơ sở với từ khóa “ảo”.

Tại sao chúng ta sử dụng Virtual Destructor?

Khi việc thực thi các hàm thành viên của lớp hoàn tất hoặc việc thực thi phương thức main() sắp kết thúc, hàm hủy sẽ tự động được gọi để giải phóng bộ nhớ được cấp phát trong quá trình tạo đối tượng. Bây giờ, tại sao chúng ta sử dụng hàm hủy ảo? Khi lớp cơ sở bị xóa trỏ đến lớp dẫn xuất, con trỏ (*) được sử dụng ở đây. Hàm hủy của lớp cơ sở chỉ được gọi trong quá trình này. Trình hủy lớp dẫn xuất không được gọi dẫn đến các vấn đề. Một trong số đó là vấn đề rò rỉ bộ nhớ. Để tránh sự cố này và làm cho mã của chúng tôi an toàn, chúng tôi hầu như hủy đối tượng để giải phóng không gian bộ nhớ đã được phân bổ trong quá trình tạo đối tượng bằng cách xóa hàm hủy của lớp cơ sở.

Ví dụ cơ bản về C++ không có Virtual Destructor

Hãy xem chương trình hoạt động như thế nào mà không có hàm hủy ảo bằng một chương trình đơn giản xóa con trỏ.

Mã số:

#include

sử dụng không gian tên std ;
lớp Parent_Class0
{
công cộng :
Phụ huynh_Lớp0 ( )
{ cout << 'Trình xây dựng lớp cha' << kết thúc ; }
~Parent_Class0 ( )
{ cout << 'Kẻ hủy diệt lớp cha' << kết thúc ; }
} ;
lớp Con_1 : công khai Parent_Class0
{
công cộng :
Con_1 ( )
{ cout << 'Người xây dựng lớp con' << kết thúc ; }
~Con_1 ( )
{ cout << 'Kẻ hủy diệt lớp con' << kết thúc ; }
} ;
int chủ yếu ( )
{
Phụ huynh_Lớp0 * con trỏ = Con mới_1 ( ) ;
xóa con trỏ ;
trở lại 0 ;
}

Mã này giải thích cách mã thực thi mà không có bộ hủy ảo. Trước hết, hãy tạo một lớp có tên là “Parent_Class0” lớp này sẽ là lớp cha. Bên trong lớp này, tạo hàm tạo và hàm hủy. Như chúng ta đã biết, hàm tạo và hàm hủy được đặt tên giống như lớp. Hàm hủy được biểu diễn tương tự như hàm tạo nhưng nó có ký hiệu (~) để phân biệt nó với hàm tạo. Bên trong hàm tạo và hàm hủy, in một thông báo bằng cách sử dụng “cout<<”. Bây giờ, hãy tạo một lớp khác là “Child_1”. Lớp này được dẫn xuất từ ​​lớp cha, “Parent_Class0”. Lớp dẫn xuất có hàm tạo và hàm hủy chứa thông báo cần in trên màn hình đầu ra.

Trong phương thức main(), chúng ta tạo một thể hiện của “Parent_Class0” và gán một lớp dẫn xuất cho nó. Điểm quan trọng cần nhớ trong trường hợp này là chúng ta sử dụng một con trỏ để truy xuất lớp cha. Khi nó đi vào bên trong lớp cha, nó sẽ thực thi hàm tạo của lớp cha. Sau đó, nó đi đến lớp con và thực thi hàm tạo của nó. Trước khi thực hiện hàm hủy của lớp con, nó phải thực hiện hàm hủy của lớp cha. Trình biên dịch thực hiện hàm hủy của lớp cha và kết thúc lớp mà không thực hiện hàm hủy của lớp con. Đó là vấn đề; nó không giải phóng bộ nhớ của lớp con. Nó đại diện cho hàm tạo của lớp cha, hàm tạo của lớp con và hàm hủy của lớp cha. Điều đó cho thấy hàm hủy của một lớp con không được thực thi. Sau khi thực hiện xong, chúng ta xóa con trỏ trong hàm main().

Đầu ra:

Ví dụ C++ với Virtual Destructor

Hãy thảo luận về hàm hủy ảo bằng một đoạn mã đơn giản để phân biệt cách nó hoạt động khi có và không có hàm hủy ảo.

Mã số:

#include

sử dụng không gian tên std ;
lớp Parent_Class0
{
công cộng :
Phụ huynh_Lớp0 ( )
{ cout << 'Trình xây dựng lớp cha' << kết thúc ; }
ảo ~ Parent_Class0 ( )
{ cout << 'Kẻ hủy diệt lớp cha' << kết thúc ; }
} ;
lớp Con_1 : công khai Parent_Class0
{
công cộng :
Con_1 ( )
{ cout << 'Người xây dựng lớp con' << kết thúc ; }
ảo ~Child_1 ( )
{ cout << 'Kẻ hủy diệt lớp con' << kết thúc ; }
} ;
int chủ yếu ( )
{
Phụ huynh_Lớp0 * con trỏ = Con mới_1 ( ) ;
xóa con trỏ ;
trở lại 0 ;
}

Chương trình đầu tiên giải thích vấn đề mà chúng ta đang gặp phải khi không có hàm hủy ảo. Bây giờ, mã này sẽ giải quyết vấn đề đó bằng cách sử dụng hàm hủy ảo. Đầu tiên, sao chép mã đầu tiên và chỉ cần thêm một từ khóa vào hai vị trí trong chương trình này. Từ đó là “ảo”. Chèn từ này với hàm hủy của lớp cha, “Parent_Class0”. Tương tự, đề cập điều này với hàm hủy của lớp con là “Child_1” được dẫn xuất từ ​​lớp cha. Từ khóa “ảo” này tạo ra một chút thay đổi và nó thực thi hàm hủy của lớp con “Child_1” trước. Sau đó, nó thực thi hàm hủy của lớp cha, “Parent_Class0”. Phần còn lại của chương trình hoạt động giống như nó hoạt động mà không có hàm hủy ảo. Bằng cách thêm đoạn mã nhỏ này, chúng ta có thể tiết kiệm bộ nhớ khỏi rò rỉ. Bây giờ, nó hiển thị bốn thông báo trên bảng điều khiển. Đầu tiên, hàm tạo của lớp cha, sau đó là hàm tạo của lớp con, hàm hủy của lớp con và hàm hủy của lớp cha. Cuối cùng, chúng ta xóa con trỏ trong phương thức main().

Đầu ra:

C++ Ví dụ về Pure Virtual Destructor

Trong mã này, chúng ta sẽ nói về hàm hủy ảo thuần túy, cách thức hoạt động của nó và nó khác với hàm hủy ảo như thế nào.

Mã số:

#include

lớp Parent_0 {
công cộng :
ảo ~Parent_0 ( ) = 0 ;
} ;
Phụ huynh_0 :: ~Parent_0 ( )
{
tiêu chuẩn :: cout << 'Xin chào, tôi là Kẻ hủy diệt thuần túy. Bạn đã gọi tôi!' ;
}
lớp Con_0 : cha mẹ công khai_0 {
công cộng :
~Con_0 ( ) { tiêu chuẩn :: cout << 'Kẻ hủy diệt có nguồn gốc ở đây \N ' ; }
} ;

int chủ yếu ( )
{
Phụ huynh_0 * ptr_0 = Con mới_0 ( ) ;
xóa ptr_0 ;
trở lại 0 ;
}

Lớp cha “Parent_0” được tạo ở bước đầu tiên của mã. Bên trong nó, tạo hàm hủy gốc ảo và gán nó bằng 0. Điều này đặt hàm hủy ảo thành hàm hủy ảo thuần túy, điều đó có nghĩa là lớp cha mẹ hiện là trừu tượng và chúng ta không thể tạo các thể hiện của lớp này. Bên ngoài lớp cha “Parent_0”, định nghĩa các hàm hủy và std::cout. Văn bản cần thiết được hiển thị bằng cách sử dụng std::cout. Sau đó, lấy một lớp “Child_0” từ lớp cha và định nghĩa hàm hủy của nó. Bên trong hàm hủy, in một tin nhắn. Trong hàm main(), tạo con trỏ của lớp cha và gán lớp con cho nó.

Trình biên dịch chuyển đến lớp cha “Parent_0”. Khi con trỏ được tạo, hàm tạo của nó sẽ tự động được gọi. Sau đó, trình biên dịch đi vào lớp con để gọi hàm tạo của nó. Sau khi thực thi thành công hàm tạo, nó sẽ thực thi hàm hủy của một lớp con “Child_0”. Sau đó, nó thực thi hàm hủy của lớp cha. Bằng cách này, chúng ta có thể tạo một hàm hủy ảo thuần túy. Nó không được khuyến khích sử dụng nó bởi vì bằng cách sử dụng phương thức này, lớp cha trở nên trừu tượng khiến nó trở nên vô dụng. Phương pháp chủ yếu được sử dụng là hàm hủy ảo và đó là một phương pháp hay.

Đầu ra:

Phần kết luận

Chúng ta đã tìm hiểu về hàm hủy ảo bắt đầu từ khái niệm OOP cho đến các hàm tạo và hàm hủy. Sau khi giải thích tất cả những điều này, chúng ta đã thảo luận chi tiết về hàm hủy ảo với các ví dụ mã hóa và hàm hủy ảo thuần túy. Trước khi giải thích hàm hủy ảo, chúng ta phải biết về hàm tạo, hàm hủy và tính kế thừa. Trong kế thừa, chúng ta kế thừa các lớp từ lớp cha. Các lớp con có thể nhiều hơn một nhưng lớp cha thì chỉ có một. Các hàm hủy ảo và các hàm hủy ảo thuần túy được áp dụng trong kế thừa để tránh rò rỉ bộ nhớ. Từ ví dụ cơ bản đến ví dụ nâng cao, chúng tôi đã trình bày mọi thứ bạn nên biết để bắt đầu sử dụng và hầu như phá hủy bộ nhớ của lớp dẫn xuất.