2010-09-13 21 views
16

Tôi không thấy câu trả lời cho câu hỏi này trong C++ Faq lite:Force destructors ảo? C++

Làm cách nào để xác định lớp cơ sở để mọi lớp thừa hưởng nó là bắt buộc để xác định hàm hủy?

Tôi đã cố gắng chạy chương trình này

http://codepad.org/wFcE71w3 Với lỗi

In function `Test::~Test()': 
t.cpp:(.gnu.linkonce.t._ZN4TestD0Ev+0x1e): undefined reference to `VDtor::~VDtor()' 
In function `Test::~Test()': 
t.cpp:(.gnu.linkonce.t._ZN4TestD1Ev+0x1e): undefined reference to `VDtor::~VDtor()' 

Vì vậy, là nó có thể?

+17

+1 cho ví dụ có thể là ví dụ hiệu quả nhất về không gian mà tôi đã thấy từ trước tới nay. :-D – DevSolar

+1

Tại sao? Điểm bắt buộc người dùng viết thêm mã là gì? Nếu bạn đã làm sạch, hãy tự làm, đừng đặt gánh nặng lên người dùng của bạn; nếu bạn không, nó vô dụng. Bạn có thể cung cấp một ví dụ về tình huống thực sự hữu ích không? –

+0

@Matthieu M .: Mã được tạo ra chỉ vượt qua void * và con được tạo ra sau đó cha mẹ sau đó các chức năng ngẫu nhiên theo thứ tự ngẫu nhiên để vượt qua params/con cho cha mẹ. Rất bừa bộn. Mỗi cấu trúc sẽ nhận được một void * và tôi cần phải nhớ để làm sạch nó lên. Có lẽ auto_ptr sẽ giải quyết nó nhưng tôi không chắc chắn về tác dụng phụ và một nửa của các lớp học dường như được thực hiện. –

Trả lời

17

Đó là "có thể" theo một nghĩa nào đó (nếu mục tiêu của bạn là lớp dẫn xuất vẫn trừu tượng nếu không). Nhưng nó sẽ không cho kết quả bạn muốn: Bởi vì trình biên dịch sẽ tạo ra một destructor chính nó ngầm nếu người lập trình đã không làm như vậy.

Đó là để không có thể buộc tác giả của lớp dẫn xuất tuyên bố rõ ràng một hàm tạo.

(chỉnh sửa: Giống như @chubsdad ghi chú lưu ý, lỗi trong mã cụ thể của bạn là do bạn cần xác định trình phá hủy được khai báo rõ ràng của lớp cơ sở).


Sửa: Chỉ cần cho vui, có tình huống mà necessiate một constructor tuyên bố một cách rõ ràng. Hãy xem xét những điều sau

struct Viral { 
    struct Dose { }; 
protected: 
    ~Viral() throw (Dose) { } 
}; 

struct Base { 
    virtual ~Base() throw() { } 
}; 

struct Derived : Base, Viral { }; 

Mã này sẽ không biên dịch vì mặc nhiên tuyên bố ~Derived sẽ có một đặc điểm kỹ thuật ngoại lệ throw (Dose) đó là lỏng hơn so với những gì ~Base có - vì vậy nó vi phạm các yêu cầu mà overriders sẽ không có một đặc điểm kỹ thuật ngoại lệ lỏng hơn. Bạn sẽ cần phải tuyên bố một cách rõ ràng destructor một cách thích hợp

struct Derived : Base, Viral { ~Derived() throw() { } }; 

Nhưng điều này không thực sự là một giải pháp cho vấn đề của bạn, bởi vì các lớp thừa kế cần phải "hợp tác" vào một trong hai bắt nguồn từ Viral hoặc đặt nó như là một thành viên dữ liệu không tĩnh . Nó cũng rất xấu xí :)


Edit: Sau đây có vẻ là một cách tiêu chuẩn phù hợp để làm điều đó

struct Viral { 
    struct Dose { }; 
protected: 
    ~Viral() throw (Dose) { } 
}; 

struct Base : virtual Viral { 
    virtual ~Base() throw() { } 
}; 

Clang và GCC (starting with v4.6) từ chối bất kỳ lớp được thừa kế của Base có một hàm hủy ngầm được khai báo ngầm, bởi vì nó có một đặc tả ngoại lệ không tương thích (bất kỳ lớp dẫn xuất nào sẽ gọi trực tiếp ~Viral, thay vì gián tiếp bằng cách gọi ~Base, tiêu chuẩn nói). Comeau chấp nhận điều này, nhưng tôi mạnh mẽ nghi ngờ rằng nó không phù hợp về vấn đề này.

+1

+1: Tôi hoàn toàn quên mất hàm hủy ngầm trong khi trả lời câu hỏi này. – Chubsdad

+0

Vì vậy, điều này có nghĩa là Không, không thể ép buộc một lớp dẫn xuất để định nghĩa một dtor? –

+1

@acid tôi sẽ nói rằng không thể buộc các lập trình viên xác định rõ ràng một destructor trong một lớp dẫn xuất. Bạn có thể vui lòng cho thấy những gì bạn cần này cho? –

1

Mọi lớp đều có trình phá hủy, bất kể. Tuyên bố một destructor ảo trong cơ sở đảm bảo rằng trẻ em sẽ có destructors ảo. Điều này không có nghĩa là người lập trình sẽ cần phải khai báo một cách rõ ràng một trình phá hủy - đó sẽ không phải là một điều tốt, dù sao đi nữa.Tất cả điều đó có nghĩa là, nếu một destructor được khai báo, nó sẽ là ảo.

+1

Khai báo dtor của cơ sở là ảo cũng có nghĩa là dtor được khai báo ngầm trong bất kỳ lớp dẫn xuất nào sẽ là ảo. Mà, như bạn nói, là tất cả những gì bạn cần. –

+0

@Fred: Vâng, tôi nên rõ ràng hơn trong việc giải thích rằng ngay cả những kẻ phá hoại được khai báo ngầm trong các lớp con sẽ luôn là ảo. Khi ảo, luôn ảo. Cảm ơn vì đã chỉ ra sự thiếu rõ ràng của tôi ở đây. –

+0

Nhìn vào nó một lần nữa, "nếu một destructor được khai báo" là nơi tôi nhìn thấy vấn đề: một dtor là * luôn luôn * tuyên bố, hoặc bởi các lập trình viên hoặc ngầm của trình biên dịch. (Điều này có vẻ rõ ràng hơn nhiều so với bình luận trước đây của tôi.) –

0

Khi thử nghiệm bị hủy, nó sẽ gọi đó là trình phá hủy lớp cơ sở, không tồn tại. Bạn chỉ cần khai báo nó trống nếu bạn không có logic hủy diệt cần thiết.

1
struct VDtor { virtual ~VDtor()=0; }; 
VDtor::~VDtor() { } // <== Implementation. 
struct Test:VDtor { ~Test(){} }; 
int main() { delete new Test; return 0; } 

Để khắc phục lỗi bạn phải thực thi VDtor :: ~ VDtor() như trên.

+0

Nhưng điều đó không bắt nguồn từ lớp để thực hiện destructor riêng của họ. –

+4

@ acidzombie24: Hoặc là một lớp cần dtor không trống và sau đó không có gì cơ sở có thể làm sẽ giúp đỡ hoặc ngầm và trống dtor là đủ tốt và sau đó không có điểm chính tả nó ra một cách rõ ràng, IMHO. – wilx