Destructor Trong C++

Destructor Trong C++

Trong bài học hôm nay chúng ta tiếp tục tìm hiểu về hàm hủy (Destructor) trong C++. Mục đích của hàm hủy trong C++ là gì? Cách sử dụng hàm hủy như thế nào? Chúng ta sẽ cùng tìm hiểu trong nội dung sau đây.

I. Hàm Destructor Trong C+Là Gì

Hàm hủy (Destructor) trong C++ ngược lại với hàm xây dựng, trong khi hàm xây dựng dùng để khởi tạo giá trị cho đối tượng thì hàm hủy dùng để hủy đối tượng.

Chỉ có duy nhất một hàm hủy trong 1 lớp. Hàm hủy tự động được gọi. Nếu như chúng ta không định nghĩa hàm hủy thì mặc định trình biên dịch sẽ tự tạo ra 1 hàm hủy mặc nhiên

Cũng giống như hàm xây dựng, hàm hủy được định nghĩa có cùng tên với tên lớp, khôn có bất cứ kiểu gì trả về kể cẳ kiểu void, tuy nhiên phải có dấu ~ trước tên của hàm hủy.

Lưu ý: Hàm hủy (Destructor) không có bất cứ tham số nào

Cú pháp

Cú pháp của hàm hủy (Destructor) trong C++ như sau:

Cú pháp
~TenLop() { };

Ví dụ cụ thể là lớp nhân viên, thì chúng ta sẽ tạo hàm hủy cho lớp nhân viên như sau:

Ví dụ
class NhanVien {  
   public:  
        ~NhanVien(){};
};

Ví dụ

Chúng ta cùng xem xét một ví dụ đơn giản nhất về hàm hủy trong C++ như sau:

Ví dụ

#include <iostream>  
using namespace std;  
class NhanVien  {  
   public:  
        NhanVien() {    
            cout << "Ham xay dung duoc goi" << endl;    
        }    
        ~NhanVien() {    
            cout << "Ham huy duoc goi" << endl;    
        }  
};  
int main(void) {  
    NhanVien n1;   
    NhanVien n2; 
    return 0;  
}
Hàm Destructor Trong C+Là Gì
Hàm Destructor Trong C+Là Gì

II. Khi Nào Hàm Destructor Được Gọi

Hàm hủy (Destructor) trong C++ được gọi tự động lúc đối tượng đi ra khỏi phạm vi:

  • Kết thúc hàm
  • Kết thúc chương trình
  • Kết thúc 1 block
  • Toán tử delete được gọi

Có hai hạn chế lúc dùng hàm hủy đó là:

  • Chúng ta không thể lấy địa chỉ của nó
  • Lớp con không có thừa kế hàm hủy từ lớp cha của nó
Khi Nào Hàm Destructor Được Gọi
Khi Nào Hàm Destructor Được Gọi

III. So Sánh Hàm Destructor Với Hàm Constructor

+ Giống Nhau:

Hàm tạo và hàm hủy là những hàm thành viên có cùng tên với lớp của chúng. Loại cũ constructor giúp khởi tạo một đối tượng. Ngược lại, a người phá hủy khác với hàm tạo sẽ xóa hàm tạo đã tạo khi nó không được sử dụng.

Đôi khi nó được yêu cầu khởi tạo 1 số phần của một đối tượng trước lúc nó có thể được sử dụng. Ví dụ, chúng ta đang thao tác trên ngăn xếp, trước khi chúng ta thực hiện bất kỳ hành động nào, đỉnh của ngăn xếp phải luôn được đặt bằng 0. Tính năng khởi tạo tự động này được thực hiện thông qua ‘Constructor’.

Giống như, trường hợp 1 đối tượng cần thực thi 1 số mã trước lúc nó bị phá hủy. Ví dụ: nếu một đối tượng cần đóng một tệp mà nó đã mở, trước khi nó bị phá hủy. Nó có thể được thực hiện với sự trợ giúp của ‘Destructor’. Bây giờ, hãy tổng quan về một số điểm khác biệt cơ bản giữa hàm tạo và hàm hủy với sự trợ giúp của biểu đồ so sánh

+ Khác Nhau:

– Biểu đồ so sánh:

Cơ sở để so sánh Constructor Kẻ hủy diệt
Mục đích Nó cấp phát bộ nhớ cho 1 đối tượng. Nó phân bổ bộ nhớ của một đối tượng.
Tờ khai class_name (các đối số nếu có) {}; ~ class_name (không có đối số) {};
Tranh luận Hàm tạo chấp nhận đối số Trình hủy không chấp nhận bất kỳ đối số nào.
Kêu gọi Hàm tạo được gọi tự động, trong lúc đối tượng được tạo. Bộ hủy được gọi tự động, lúc khối được thoát hoặc chương trình kết thúc.
Đang làm việc Constructor cho phép một đối tượng khởi tạo một số giá trị của nó trước đó, nó được sử dụng. Destructor cho phép một đối tượng thực thi một số mã tại thời điểm nó bị phá hủy.
Thứ tự thực hiện Hàm tạo được gọi theo thứ tự liên tiếp. Hàm hủy được gọi theo thứ tự ngược lại của hàm tạo.
Bằng số Có thể có nhiều hàm tạo trong một lớp. Luôn có một hàm hủy duy nhất trong lớp.
Copy Constructor Copy constructor cho phép một constructor khai báo và khởi tạo một đối tượng từ một đối tượng khác. Không có khái niệm như vậy.
Quá tải Các trình xây dựng có thể bị quá tải. Bộ hủy không thể bị quá tải.

– Định nghĩa của Constructor

A constructor về căn bản là 1 hàm thành viên của lớp, nó khởi tạo đối tượng và cấp phát bộ nhớ cho nó. Các hàm tạo có thể được xác định dễ dàng vì chúng được khai báo và định nghĩa cùng tên với tên của lớp. Một phương thức khởi tạo không có bất kỳ kiểu trả về nào; vì vậy, chúng không trả lại bất cứ thứ gì, thậm chí không phải là ‘void’. Một Constructor luôn được định nghĩa trong phần public của 1 lớp.

Có thể có nhiều hàm tạo trong 1 lớp; chúng có thể được phân biệt dựa trên số lượng và loại đối số được truyền vào. Nếu có nhiều hàm tạo trong một lớp; phương thức khởi tạo ngầm định (hàm tạo không làm gì) phải được định nghĩa cùng với chúng; nó không làm gì ngoài, đáp ứng trình biên dịch.

Các hàm tạo cũng có thể được định nghĩa với những đối số mặc định. Trong khi đó, họ cũng khởi tạo đối tượng “động”. Các hàm tạo không thể được kế thừa, cũng không thể là ảo, nhưng chúng có thể bị quá tải. Họ không thể được giới thiệu đến địa chỉ của họ.

– Các loại cấu tạo

Về cơ bản có ba loại cấu trúc – Cấu trúc mặc định, Tham số và Sao chép.

  • Nhà xây dựng mặc định: Nó là một hàm tạo mà không có đối số nào được đưa ra cho hàm tạo. Hàm tạo mặc định không có tham số, nhưng các giá trị cho hàm tạo mặc định có thể được truyền theo mặc định (động).
  • Trình tạo tham số: Kiểu hàm tạo này nhận các đối số; chúng ta có thể chuyển các giá trị khác nhau cho các thành viên dữ liệu làm đối số.
  • Copy Constructor: Copy constructor khác với các loại constructor khác vì nó chấp nhận địa chỉ của đối tượng khác làm đối số.

– Thực hiện hàm tạo

lớp Const {int a, b; public: Const () // hàm tạo không có tham số {a = 0; b = 0; } Const (int c, int d) {// hàm tạo với tham số a = c; c = d; }}; int main () {Const C1; C2 (10,20); // câu lệnh này gọi hàm tạo}

Khi C1 được tạo, một hàm tạo không có tham số nào được thực thi, vì C1 không truyền bất kỳ tham số nào. Trong khi, khi C2 được tạo, một hàm tạo có tham số sẽ được thực thi, vì nó đang truyền hai số nguyên cho hàm tạo.

– Định nghĩa của Destructor

A Kẻ hủy diệt cũng là một hàm thành viên của một lớp, nó sẽ phân bổ bộ nhớ được cấp phát cho một đối tượng. Nó được định nghĩa cùng tên với tên của một lớp, đứng trước dấu ngã (~) Biểu tượng. Các hàm hủy luôn được gọi theo thứ tự ngược lại của các hàm tạo.

Luôn có một hàm hủy duy nhất trong một lớp, vì nó không chấp nhận bất kỳ đối số nào. Các đối tượng địa phương bị phá hủy ngay sau khi quyền kiểm soát của việc thực hiện thúc đẩy khối; mặt khác, các đối tượng toàn cục bị phá hủy khi toàn bộ chương trình kết thúc.

Một trình hủy được gọi ngầm bởi một trình biên dịch. Nếu các lớp được kế thừa và một lớp được dẫn xuất từ ​​lớp cha và cả lớp con và lớp cha đều có hàm hủy; sau đó, hàm hủy của lớp dẫn xuất được gọi đầu tiên, tiếp theo là hàm hủy của lớp cha.

– Triển khai Trình hủy

lớp Const {int a, b; public: Const (int c, int d) // hàm tạo có tham số. {a = c; c = d; cout “giá trị của a và b là” ab ” n”; } ~ Const () // hàm hủy đang được gọi. {cout “đối tượng C1 bị phá hủy” ” n”; }}; int main () {Const C1 (10,20); }

Khi đối tượng C1 được tạo, một hàm tạo có hai tham số kiểu số nguyên được gọi và thành viên “a, b” được khởi tạo và giá trị của “a, b” được in ra. Sau khi trình hủy đó được gọi và in ra thông báo “đối tượng C1 bị phá hủy”.

Need of Destructor

Việc tạo hàm tạo sẽ tiêu tốn một lượng không gian bộ nhớ, vì nó cuối cùng sẽ cấp phát bộ nhớ cho các đối tượng. Bộ nhớ được cấp phát này phải được phân bổ trước khi hủy các đối tượng để giải phóng tài nguyên cho các tác vụ khác. Bộ hủy cực kỳ hữu ích cho mục đích đã định, nó phá hủy hiệu quả các đối tượng và thực hiện các nhiệm vụ dọn dẹp để giải phóng bộ nhớ.

So Sánh Hàm Destructor Với Hàm Constructor
So Sánh Hàm Destructor Với Hàm Constructor

IV. Bài Tập Hàm Destructor Trong C++

Chúng ta cùng xem một class đơn giản có sử dụng hàm destructor:

/**
* Techacademy.edu.vn - Kênh thông tin IT hàng đầu Việt Nam
*
* @author cafedevn
* Contact: cafedevn@gmail.com
* Fanpage: https://www.facebook.com/cafedevn
* Instagram: https://instagram.com/cafedevn
* Twitter: https://twitter.com/CafedeVn
* Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
*/

#include <iostream>
#include <cassert>
 
class IntArray
{
private:
   int *m_array;
   int m_length;
 
public:
   IntArray(int length) // constructor
   {
      assert(length > 0);
 
      m_array = new int[length]{};
      m_length = length;
   }
 
   ~IntArray() // destructor
   {
      // Dynamically delete the array we allocated earlier
      delete[] m_array;
   }
 
   void setValue(int index, int value) { m_array[index] = value; }
   int getValue(int index) { return m_array[index]; }
 
   int getLength() { return m_length; }
};
 
int main()
{
   IntArray ar(10); // allocate 10 integers
   for (int count{ 0 }; count < ar.getLength(); ++count)
      ar.setValue(count, count+1);
 
   std::cout << "The value of element 5 is: " << ar.getValue(5) << '\n';
 
   return 0;
} // ar is destroyed here, so the ~IntArray() destructor function is called here

Mẹo nhỏ

Nếu bạn thử biên dịch đoạn code trên và bị lỗi sau:

If you compile the above example and get the following error:

error: 'class IntArray' has pointer data members [-Werror=effc++]|
error:   but does not override 'IntArray(const IntArray&)' [-Werror=effc++]|
error:   or 'operator=(const IntArray&)' [-Werror=effc++]|

Để khắc phúc lỗi này, bạn có thể loại bỏ cờ “-Weffc++” khỏi compile settings (những thiết lập về biên dịch) cho ví dụ này, hoặc là bạn có thể thêm hai dòng code sau vào trong class IntArray:

IntArray(const IntArray&) = delete;
IntArray& operator=(const IntArray&) = delete;

Chúng ta sẽ thảo luận về chức năng của hai câu lệnh này trong chương sau.

Đoạn chương trình trên sẽ in ra:

The value of element 5 is: 6

Trên dòng đầu tiên, chúng ta đã khởi tạo 1 đối tượng mới của class IntArray, được gọi là ar, và truyền vào độ dài mảng là 10. Việc khởi tạo này sẽ gọi tới hàm constructor nhằm cấp phát bộ nhớ động cho những biến thành viên của class IntArray.

Chúng ta bắt buộc sử dụng cấp phát động tại đây bởi vì chúng ta không thể biết được tại thời điểm biên dịch (compile time) thì độ dài của mảng là bao nhiêu (caller – đối tượng gọi hàm sẽ quyết định điều đó).

Khi hàm main() kết thúc, lúc này đối tượng ar đã nằm ngoài phạm vi đoạn code mà chương trình đang chạy trên đấy (tức là ar đã goes out of scope). Điều này sẽ làm cho hàm destructor ~IntArray() được gọi, để xóa đi mảng mà chúng ta đã cấp phát bên trong phần thân hàm của constructor!

Bài Tập Hàm Destructor Trong C++
Bài Tập Hàm Destructor Trong C++

Đánh Giá Chất Lượng Bài Viết

Average rating 0 / 5. Vote count: 0

No votes so far! Be the first to rate this post.

Leave a Reply

Your email address will not be published. Required fields are marked *

Hotline: 0984.876.750
Chat Facebook
Gọi điện ngay