我看过代码,其中构造函数已被声明为私有,而析构函数是公共的。这种声明有什么用?析构函数是否必须是公共的,以便在继承期间调用是可能的,还是代码中的错误?
问题可能看起来有点简短,但我真正想知道的是,当构造函数需要私有时遵守C ++规则时是否有公共析构函数?
答案 0 :(得分:6)
将构造函数创建为私有,但析构函数为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
删除了自己,see here以获取执行此操作时要考虑的事项列表。
<强>的Singleton 强>
单例类中私有构造函数和析构函数的一个主要优点是强制用户仅以 方式设计代码。无法创建流氓单例对象(因为它在编译时强制执行),并且用户无法删除单例实例(再次,在编译时强制执行)。
例如:
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
的创建。您可以使用工厂方法对MyFactoryObject
执行任何初始化(例如:设置GUID,注册到DB),并且在使用工厂方法的任何地方,也将执行初始化代码。
这只是一些如何使用私有构造函数和析构函数来强制正确使用API的示例。如果你想变得棘手,你也可以结合所有这些设计模式;)
答案 1 :(得分:4)
第一件事:析构函数可以是私有的。
在需要构造函数时有一个公共析构函数 私人遵守C ++规则?
它完全适用于C ++。事实上,这种情况的一个很好的例子是单例模式,其中构造函数是私有的,析构函数是公共的。
答案 2 :(得分:1)
如果要阻止创建类的多个实例,请将构造函数设为私有。这样你就可以控制动作的创建,而不是它们的破坏。因此,析构函数可能是公开的。
答案 3 :(得分:0)
在我脑海中的一个例子,让我们说你想要将类实例数限制为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
答案 4 :(得分:0)
对象的所有者需要访问析构函数才能销毁它。如果构造函数是私有的,则必须有一些可访问的函数来创建对象。如果该函数将构造对象的所有权转移给调用者(例如,返回指向免费存储上的对象的指针),则调用者在决定删除该对象时必须有权访问析构函数。
答案 5 :(得分:0)
以相反的顺序。
析构函数是否需要公开,以便在继承期间调用是可能的,还是代码中的错误?
实际上,为了继承工作,析构函数至少应为protected
。如果从具有private
析构函数的类继承,则不能为派生类生成析构函数,这实际上会阻止实例化(您仍然可以使用static
方法和属性)。
这种声明的用途是什么?
请注意,即使构造函数是private
,也没有进一步指示该类具有(默认生成的)公共复制构造函数和复制赋值运算符。这种模式经常发生在:
命名构造函数idiom的示例:
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);