【发布时间】:2016-02-11 11:57:00
【问题描述】:
假设我有一个封装了一个(或多个)成员的类,必须以某种方式对其进行初始化,没有它就没有合理的方式使用该类(所以我不想让它成为可选的) . 像这样在其构造函数中运行初始化是否更好:
class MyClass
{
MyClass()
{
if(!obj.initialize()
throw ...;
}
private:
MyObject obj;
}
或者您会建议以下设计:
class MyClass
{
MyClass()
{
}
bool initialize()
{
return obj.initialize();
}
private:
MyObject obj;
}
第一个看起来很吸引人,因为我可以保证在构造函数运行后满足使用我的类的所有要求,并且我可以通过抛出异常来报告任何错误。
第二个看起来不错,因为它不会用直觉上不属于那里的东西重载构造函数,特别是当初始化例程变得复杂时,即创建小部件、打开数据库连接、初始化第 3 方库等。在很多我正在使用的遗留代码,ctors 充斥着参数和初始化的东西,可能在这种臃肿的对象构造完成之前运行了数千行代码。尝试将这些重构为更干净的东西在某些时候确实很难,因为涉及的依赖项太多。这就是我提出问题的原因。
我可以看到设计#2 的最大缺点是我需要一个公共初始化例程,客户端必须记住调用它。但是由于这可以并且可能会被遗忘,我必须跟踪和检查所有公共成员的初始化状态,并以某种方式处理错误(可能一个断言就可以了)。如果我选择设计#1,这也会使我的课堂上出现一些不存在的东西。
那么我最好的选择是什么?
【问题讨论】:
-
对我来说,这听起来像是在自相矛盾:“没有它就没有合理的方法来使用类”,然后是“用直觉上不属于那里的东西重载构造函数”。将对象置于一致状态是构造函数的工作,因此任何需要这样做的东西都应该交给构造函数。
-
你不必有一个臃肿的构造函数。您仍然可以将代码正确地组织到模块/函数中,然后从构造函数中调用它们。您可以有一个混合解决方案,其中您的
init方法是私有的,您可以从构造函数中调用它。这样,如果初始化失败,您可以抛出。 -
你可以创建函数来创建每个子对象(所以一个子对象一行)。
-
当您无法建立类的不变量时,更喜欢从构造函数中抛出。这样您就不必担心漂浮的无效对象。否则,创建一个将 2 个步骤(创建和初始化)包装在一起的工厂。
-
如果
MyObject的构造函数自己初始化,MyClass就不用费心了。
标签: c++ constructor initialization