[英]Use of public destructor when the constructor is private
我已經看到了代碼,其中構造函數已被聲明為私有,而析構函數是公共的。 這種聲明有什么用? 析構函數是否需要公開,以便在繼承期間調用是可能的,還是代碼中的錯誤?
這個問題看起來似乎有點簡短,但我真正想知道的是,當構造函數需要私有時遵守C ++規則時是否有公共析構函數?
將構造函數創建為私有,但將析構函數創建為public,具有許多實際用途。
您可以使用此范例:
上面我暗示你可以使用私有構造函數和析構函數來實現幾種設計模式。 嗯,這是怎么...
參考計數
在對象中使用私有析構函數會使自己適用於引用計數系統。 這使開發人員可以更好地控制對象的生命周期。
class MyReferenceObject
{
public:
static MyReferenceObject* Create()
{
return new MyReferenceObject();
}
void retain()
{
m_ref_count++;
}
void release()
{
m_ref_count--;
if (m_ref_count <= 0)
{
// Perform any resource/sub object cleanup.
// Delete myself.
delete this; // Dangerous example but demonstrates the principle.
}
}
private:
int m_ref_count;
MyReferenceObject()
{
m_ref_count = 1;
}
~MyReferenceObject() { }
}
int main()
{
new MyReferenceObject(); // Illegal.
MyReferenceObject object; // Illegal, cannot be made on stack as destructor is private.
MyReferenceObject* object = MyReferenceObject::Create(); // Creates a new instance of 'MyReferenceObject' with reference count.
object->retain(); // Reference count of 2.
object->release(); // Reference count of 1.
object->release(); // Reference count of 0, object deletes itself from the heap.
}
這演示了對象如何管理自身並防止開發人員破壞內存系統。 請注意,這是一個危險的示例,因為MyReferenceObject
會自行刪除, 請參閱此處以獲取執行此操作時要考慮的事項列表。
獨生子
單例類中私有構造函數和析構函數的一個主要優點是強制用戶僅以代碼設計的方式使用它。 無法創建流氓單例對象(因為它在編譯時強制執行),並且用戶無法刪除單例實例(再次,在編譯時強制執行)。
例如:
class MySingleton
{
public:
MySingleton* Instance()
{
static MySingleton* instance = NULL;
if (!instance)
{
instance = new MySingleton();
}
return instance;
}
private:
MySingleton() { }
~MySingleton() { }
}
int main()
{
new MySingleton(); // Illegal
delete MySingleton::Instance(); // Illegal.
}
看看代碼幾乎不可能被濫用。 正確使用的MySingleton
是強制在編譯時,從而確保開發人員必須使用MySingleton
如預期。
廠
在工廠設計模式中使用私有構造函數是強制僅使用工廠來創建對象的重要機制。
例如:
class MyFactoryObject
{
public:
protected:
friend class MyFactory; // Allows the object factory to create instances of MyFactoryObject
MyFactoryObject() {} // Can only be created by itself or a friend class (MyFactory).
}
class MyFactory
{
public:
static MyFactoryObject* MakeObject()
{
// You can perform any MyFactoryObject specific initialisation here and it will carry through to wherever the factory method is invoked.
return new MyFactoryObject();
}
}
int main()
{
new MyFactoryObject(); // Illegal.
MyFactory::MakeObject(); // Legal, enforces the developer to make MyFactoryObject only through MyFactory.
}
這很有用,因為它隱藏了開發人員創建的MyFactoryObject
。 您可以使用工廠方法來執行任何initilisation為MyFactoryObject
(如:設置一個GUID,登記到數據庫中),並在任何地方使用,也initilisation代碼也將發生在工廠方法。
這只是一些如何使用私有構造函數和析構函數來強制正確使用API的示例。 如果你想變得棘手,你也可以結合所有這些設計模式;)
第一件事:析構函數可以是私有的。
當構造函數需要私有時,有一個公共析構函數遵守C ++規則嗎?
它完全適用於C ++。 事實上,這種情況的一個很好的例子是單例模式 ,其中構造函數是私有的,析構函數是公共的。
如果要阻止創建類的多個實例,則可以將構造函數設為私有。 這樣你就可以控制動作的創建,而不是它們的破壞。 因此,析構函數可能是公開的。
在我腦海中的一個例子,假設您想要將類實例數限制為0或1.例如,對於某些單例類,您希望應用程序可以臨時銷毀對象以減少內存使用量。 實現這個構造函數將是私有的,但析構函數將是公共的。 請參閱以下代碼段。
class SingletoneBigMemoryConsumer
{
private:
SingletoneBigMemoryConsumer()
{
// Allocate a lot of resource here.
}
public:
static SingletoneBigMemoryConsumer* getInstance()
{
if (instance != NULL)
return instance;
else
return new SingletoneBigMemoryConsumer();
}
~SingletoneBigMemoryConsumer()
{
// release the allocated resource.
instance = NULL;
}
private:
// data memeber.
static SingletoneBigMemoryConsumer* instance;
}
//Usage.
SingletoneBigMemoryConsumer* obj = SingletoneBigMemoryConsumer::getInstance();
// You cannot create more SingletoneBigMemoryConsumer here.
// After 1 seconds usage, delete it to reduce memory usage.
delete obj;
// You can create an new one when needed later
對象的所有者需要訪問析構函數才能銷毀它。 如果構造函數是私有的,則必須有一些可訪問的函數來創建對象。 如果該函數將構造對象的所有權轉移給調用者(例如,返回指向免費存儲上的對象的指針),則調用者在決定刪除該對象時必須有權訪問析構函數。
以相反的順序。
析構函數是否需要公開,以便在繼承期間調用是可能的,還是代碼中的錯誤?
實際上,為了繼承工作,析構函數至少應該protected
。 如果從具有private
析構函數的類繼承,則不能為派生類生成析構函數,這實際上會阻止實例化(您仍然可以使用static
方法和屬性)。
這種聲明有什么用?
請注意,即使構造函數是private
,也沒有進一步的指示,該類具有(默認生成的)公共復制構造函數和復制賦值運算符。 這種模式經常出現:
命名構造函數的例子:
class Angle {
public:
static Angle FromDegrees(double d);
static Angle FromRadian(double d);
private:
Angle(double x): _value(x) {}
double _value;
};
因為x
是否應該以度或弧度(或其他)精確化是不明確的 ,所以構造函數是private
並且提供了命名方法 。 這樣,用法使單位顯而易見:
Angle a = Angle::FromDegrees(360);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.