2008-12-09 36 views
44

Java và C# hỗ trợ khái niệm về các lớp không thể được sử dụng làm lớp cơ sở với các từ khóa finalsealed. Trong C + + tuy nhiên không có cách nào tốt để ngăn chặn một lớp học được bắt nguồn từ đó rời khỏi tác giả của lớp với một tiến thoái lưỡng nan, nên mỗi lớp có một destructor ảo hay không?Mọi lớp học có hủy diệt ảo không?


Edit: Kể từ C++ 11 này không còn đúng, bạn có thể xác định rằng một lớp là final.


Một mặt cho một đối tượng một destructor ảo có nghĩa là nó sẽ có một vtable và do đó tiêu thụ 4 (hoặc 8 trên máy 64 bit) byte thêm mỗi đối tượng cho vptr. Mặt khác, nếu một người nào đó sau đó xuất phát từ lớp này và xóa một lớp dẫn xuất thông qua một con trỏ đến lớp cơ sở, chương trình sẽ không được xác định (do sự vắng mặt của một destructor ảo), và thẳng thắn tối ưu hóa cho một con trỏ trên mỗi đối tượng là vô lý.

Trên gripping hand có trình phá hủy ảo (được cho là) ​​quảng cáo loại này có nghĩa là được sử dụng đa hình.

Một số người nghĩ rằng bạn cần một lý do rõ ràng để không sử dụng một destructor ảo (như là văn bản phụ của this question) và những người khác nói rằng bạn nên sử dụng chúng chỉ khi bạn có lý do để tin rằng lớp học của bạn có nguồn gốc từ, bạn nghĩ gì?

+0

Đã có câu hỏi về ưu điểm khuyết điểm - đây có phải là bản sao hoặc nó được dự định là cuộc thăm dò ý kiến ​​không? Nếu sau này, có thể bạn nên tạo câu trả lời "có" và "không" để bỏ phiếu, sau đó đóng câu hỏi? Tôi nghĩ đó là cách được khuyến nghị để triển khai cuộc thăm dò đa lựa chọn trên SO. –

+0

Bản sao: http://stackoverflow.com/questions/270917/why-should-i-declare-a-virtual-destructor-for-an-abstract-class-in-c, http://stackoverflow.com/questions/300986/khi-nên-bạn-không-sử dụng-ảo-destructors –

+6

"và thẳng thắn tối ưu hóa cho một con trỏ cho mỗi đối tượng là vô lý." - Nó không vô lý cho các đối tượng nhỏ. C++ 0x đang thêm một container forward_list, chính xác vì đôi khi một con trỏ trên mỗi đối tượng trên không quá nhiều - từ các yêu cầu về không gian và thời gian. –

Trả lời

26

Câu hỏi thực sự là, bạn có muốn thực thi các quy tắc về cách sử dụng lớp học của mình không? Tại sao? Nếu một lớp không có một destructor ảo, bất cứ ai sử dụng lớp biết rằng nó không có ý định được bắt nguồn từ, và những hạn chế áp dụng nếu bạn thử nó anyway. Điều đó không đủ tốt sao?

Hoặc bạn có cần trình biên dịch để ném một lỗi cứng nếu có ai đó dares để làm điều gì đó bạn không lường trước được không?

Cung cấp cho lớp một destructor ảo nếu bạn có ý định cho mọi người bắt nguồn từ nó. Nếu không, và giả sử rằng bất kỳ ai sử dụng mã của bạn đều đủ thông minh để sử dụng mã của bạn một cách chính xác.

+6

@jalf: nếu chúng bắt nguồn từ nó VÀ muốn sử dụng nó theo cách đa hình/ – Oszkar

2

Tôi sẽ "không" đối với câu hỏi chung. Không phải mỗi lớp học cần một. Nếu bạn có thể biết rằng lớp học sẽ không bao giờ được kế thừa, thì không cần phải chịu chi phí nhỏ. Nhưng nếu có cơ hội, hãy ở bên an toàn và đặt một cái ở đó.

8

Không! Các destructor ảo chỉ được sử dụng khi một đối tượng của một lớp dẫn xuất bị xóa thông qua một con trỏ lớp cơ sở. Nếu lớp của bạn không có ý định phục vụ như là cơ sở trong kịch bản này, không làm cho destructor ảo - bạn sẽ gửi một thông báo sai.

+0

Vậy làm thế nào để bạn dự đoán mỗi trường hợp duy nhất mà mã của bạn là hữu ích? Có lẽ sẽ có một số trường hợp mà lớp của bạn, có nghĩa là được sử dụng không đa hình bởi bạn chỉ hữu ích như một lớp cơ sở trong một số trường hợp rất cụ thể. – v010dya

53

Mỗi lớp trừu tượng hoặc là nên có một,

  • bảo vệ destructor, hoặc,
  • destructor ảo.

Nếu bạn có công cụ hủy không công khai, điều đó không tốt vì nó cho phép người dùng xóa thông qua con trỏ đó một đối tượng có nguồn gốc. Vì chúng ta đều biết, đó là hành vi không xác định.

Đối với một lớp học không có ý định xóa thông qua một con trỏ đến nó, không có lý do gì để có một destructor ảo. Nó sẽ không chỉ lãng phí tài nguyên, nhưng quan trọng hơn nó sẽ cung cấp cho người dùng một gợi ý sai. Chỉ cần suy nghĩ về ý nghĩa crappy nó sẽ thực hiện để cung cấp cho std::iterator một destructor ảo.

+2

Hoặc cấu trúc tm từ , sẽ ngừng là POD và do đó không còn tương thích với các quy ước gọi điện C nữa. –

+0

câu trả lời tuyệt vời, litb. Tôi sẽ thay đổi tất cả mã của tôi ngay bây giờ. –

0

Tôi sẽ thêm rằng đã có lần tôi đã gãi đầu trong một thời gian trên các destructors không nhận được gọi khi tôi quên một ảo trong cha mẹ hoặc lớp trẻ em. Tôi đoán bây giờ tôi đã biết điều đó.:)

Ai đó có thể tranh luận rằng có những lần lớp cha làm điều gì đó trong destructor của nó mà một đứa trẻ không nên làm ... nhưng đó có thể là một chỉ báo của một cái gì đó sai với cấu trúc thừa kế của bạn anyway.

4

Kiểm tra this article from Herb Sutter:

Hướng dẫn # 4: Một destructor lớp cơ sở nên là công khai và ảo, hoặc bảo vệ và nonvirtual.

+8

Lưu ý rằng anh ấy đang nói về các lớp có nghĩa là các lớp * base * câu hỏi này đặc biệt là về các lớp không được thiết kế làm lớp cơ sở. – Motti

0

Lớp cơ sở trở thành lớp trừu tượng, khi nó chứa ít nhất một hàm ảo thuần túy. Nếu Base không có destructor ảo và Derived (bắt nguồn từ Base), thì bạn có thể phá hủy an toàn đối tượng Derived thông qua một con trỏ đối tượng Derived nhưng không thông qua con trỏ đối tượng Base.

-3
include<iostream> using namespace std; 

class base { 
    public: base() { 
     cout << "In base class constructor" << endl; 
    } 

    virtual ~base() { 
     cout << "in base class destuctor" << endl; 
    } 
}; 

class derived : public base { 
    public: derived() { 
     cout << "in derived class constructor" << endl; 
    } 

    ~derived() { 
     cout << "in derived class destructor" << endl; 
    } 
}; 

int main() { 
    base *b; // pointer to the base 
    class b = new derived; // creating the derived class object using new 
    keyword; 
    delete b; 
    return 0; 
} 
+0

Tôi không thể đưa câu trả lời của tôi theo trình tự .. – ashutosh

+0

Chỉ cần dán mã của bạn, chọn tất cả và nhấp vào '{}'. Nhưng những gì bạn đăng không trả lời câu hỏi trên. Các câu trả lời chỉ có mã thường không đủ tốt ở đây, bạn cần giải thích tại sao mã bạn cung cấp trả lời câu hỏi được đăng. – Mat

+0

Bạn chưa trả lời câu hỏi - chỉ hiển thị cách thực hiện. – iblamefish

Các vấn đề liên quan