Câu trả lời:
Về cơ bản, bất cứ khi nào bạn muốn một số lớp khác chịu trách nhiệm về vòng đời của các đối tượng của lớp bạn hoặc bạn có lý do để ngăn chặn sự phá hủy của một đối tượng, bạn có thể đặt công cụ phá hủy ở chế độ riêng tư.
Chẳng hạn, nếu bạn đang thực hiện một số cách đếm tham chiếu, bạn có thể để đối tượng (hoặc người quản lý là "bạn bè" ed) chịu trách nhiệm đếm số lượng tham chiếu cho chính nó và xóa nó khi số đó bằng không. Một dtor riêng sẽ ngăn không cho bất kỳ ai khác xóa nó khi vẫn còn các tài liệu tham khảo đến nó.
Trong một trường hợp khác, nếu bạn có một đối tượng có trình quản lý (hoặc chính nó) có thể phá hủy nó hoặc có thể từ chối phá hủy nó tùy thuộc vào các điều kiện khác trong chương trình, chẳng hạn như kết nối cơ sở dữ liệu đang mở hoặc tệp được ghi. Bạn có thể có một phương thức "request_delete" trong lớp hoặc trình quản lý sẽ kiểm tra điều kiện đó và nó sẽ xóa hoặc từ chối và trả về trạng thái cho bạn biết những gì nó đã làm. Điều đó linh hoạt hơn nhiều khi chỉ cần gọi "xóa".
Một đối tượng như vậy không bao giờ có thể được tạo ra trên ngăn xếp. Luôn luôn trên đống. Và việc xóa phải được thực hiện thông qua một người bạn hoặc một thành viên. Một sản phẩm có thể sử dụng một hệ thống phân cấp Đối tượng duy nhất và trình quản lý bộ nhớ tùy chỉnh - các tình huống như vậy có thể sử dụng một dtor riêng.
#include <iostream>
class a {
~a() {}
friend void delete_a(a* p);
};
void delete_a(a* p) {
delete p;
}
int main()
{
a *p = new a;
delete_a(p);
return 0;
}
Khi bạn không muốn người dùng truy cập vào hàm hủy, tức là bạn muốn đối tượng chỉ bị phá hủy thông qua các phương tiện khác.
http://bloss.msdn.com/larryosterman/archive/2005/07/01/434684.aspx đưa ra một ví dụ, trong đó đối tượng được tham chiếu đếm và chỉ nên bị phá hủy bởi chính đối tượng khi số đếm về 0.
COM sử dụng chiến lược này để xóa cá thể. COM làm cho hàm hủy riêng tư và cung cấp giao diện để xóa thể hiện.
Dưới đây là một ví dụ về phương thức Phát hành sẽ như thế nào.
int MyRefCountedObject::Release()
{
_refCount--;
if ( 0 == _refCount )
{
delete this;
return 0;
}
return _refCount;
}
Các đối tượng COM ATL là một ví dụ điển hình của mẫu này.
Thêm vào các câu trả lời đã có mặt ở đây; Các hàm tạo và hàm hủy riêng tư khá hữu ích trong khi thực hiện một nhà máy nơi các đối tượng được tạo được yêu cầu phải được phân bổ trên heap. Nói chung, các đối tượng sẽ được tạo / xóa bởi một thành viên tĩnh hoặc bạn bè. Ví dụ về cách sử dụng thông thường:
class myclass
{
public:
static myclass* create(/* args */) // Factory
{
return new myclass(/* args */);
}
static void destroy(myclass* ptr)
{
delete ptr;
}
private:
myclass(/* args */) { ... } // Private CTOR and DTOR
~myclass() { ... } //
}
int main ()
{
myclass m; // error: ctor and dtor are private
myclass* mp = new myclass (..); // error: private ctor
myclass* mp = myclass::create(..); // OK
delete mp; // error: private dtor
myclass::destroy(mp); // OK
}
Lớp chỉ có thể bị xóa bởi chính nó. Hữu ích nếu bạn đang tạo một số thử đối tượng đếm tham chiếu. Sau đó, chỉ có phương thức phát hành có thể xóa đối tượng, có thể giúp bạn tránh lỗi.
Tôi biết bạn đã hỏi về hủy diệt tư nhân. Đây là cách tôi sử dụng những người được bảo vệ. Ý tưởng là bạn không muốn xóa lớp chính thông qua con trỏ đến lớp có thêm chức năng bổ sung cho lớp chính.
Trong ví dụ dưới đây, tôi không muốn GuiWindow bị xóa thông qua con trỏ HandlerHolder.
class Handler
{
public:
virtual void onClose() = 0;
protected:
virtual ~Handler();
};
class HandlerHolder
{
public:
void setHandler( Handler* );
Handler* getHandler() const;
protected:
~HandlerHolder(){}
private:
Handler* handler_;
};
class GuiWindow : public HandlerHolder
{
public:
void finish()
{
getHandler()->onClose();
}
virtual ~GuiWindow(){}
};
dirkgently là sai. Dưới đây là một ví dụ về đối tượng với c-tor và d-tor riêng được tạo trên stack (Tôi đang sử dụng hàm thành viên tĩnh ở đây, nhưng nó cũng có thể được thực hiện với chức năng kết bạn hoặc lớp bạn bè).
#include <iostream>
class PrivateCD
{
private:
PrivateCD(int i) : _i(i) {};
~PrivateCD(){};
int _i;
public:
static void TryMe(int i)
{
PrivateCD p(i);
cout << "inside PrivateCD::TryMe, p._i = " << p._i << endl;
};
};
int main()
{
PrivateCD::TryMe(8);
};
Mã này sẽ tạo đầu ra: bên trong PrivateCD :: TryMe, p._i = 8
Nó có thể là một cách để giải quyết vấn đề trong Windows khi mỗi mô-đun có thể sử dụng một đống khác nhau, chẳng hạn như đống Debug . Nếu vấn đề đó không được xử lý chính xác thì những điều xấu có thể xảy ra.