【发布时间】:2018-11-29 05:12:12
【问题描述】:
This question 要求以简洁的方式在 C++ 中实现静态工厂方法,this answer 描述了一种清晰的方式来实现这一点。返回值优化将使我们免于制作Object 的不必要副本,从而使这种创建Object 的方式与直接调用构造函数一样有效。在私有构造函数中将i 复制到id 的开销可以忽略不计,因为它是一个小的int。
但是,当Object 包含一个实例变量是类Foo 的实例(需要复杂的初始化逻辑)而不是一个小的原始类型时,问题和答案并未涵盖更复杂的情况。假设我想使用传递给Object 的参数构造Foo。使用构造函数的解决方案如下所示:
class Object {
Foo foo;
public:
Object(const FooArg& fooArg) {
// Create foo using fooArg here
foo = ...
}
}
在我看来,与引用的答案类似的静态工厂方法的替代方法是:
class Object {
Foo foo;
explicit Object(const Foo& foo_):
foo(foo_)
{
}
public:
static Object FromFooArg(const FooArg& fooArg) {
// Create foo using fooArg here
Foo foo = ...
return Object(foo);
}
}
在这里,将foo_ 复制到foo 的开销不再一定可以忽略不计,因为Foo 可以是任意复杂的类。此外,据我了解(这里是 C++ 新手,所以我可能错了),这段代码隐含地要求为 Foo 定义一个复制构造函数。
在这种情况下,什么是实现这种模式的类似干净但有效的方法?
为了预测关于为什么这是相关的可能问题,我考虑让构造函数具有比仅仅复制参数更复杂的逻辑作为反模式。我希望构造函数:
- 保证工作正常,不抛出异常,
- 不要在后台进行繁重的计算。
因此,我更喜欢将复杂的初始化逻辑放入静态方法中。此外,这种方法提供了额外的好处,例如即使输入参数类型相同,也可以通过静态工厂方法名称进行重载,并且可以清楚地以方法名称说明内部正在执行的操作。
【问题讨论】:
-
从 C++11 开始,您确实可以使用 移动语义。但这是一个复杂的话题;最好的答案是像 Stroustrup 这样的好书。写得很好的问题; +1。
-
严格来说,您使用公共 c'tor 的第一个版本也很昂贵。您默认初始化
foo(我假设所有初始化都很昂贵),然后您创建另一个Foo对象,并将其分配给默认构造的对象。 -
@StoryTeller 嗯,我不知道一定是这样。我认为在第一个版本中,如果我执行
foo = Foo(fooArg),那么只会调用该构造函数并且不会发生复制。我对 C++ 的了解是从 Java 开始的。无论如何,我主要关注的是 copying 而不是 initialization (即使对于潜在的大对象也可能很便宜,例如空数组初始化)。 -
@Vossler - 我建议在这里小心行事。 C++ 对象模型与 Java 非常不同。成员的初始化和复制不像在 Java 中那样不连贯。
-
直接从
fooArg初始化其foo的构造函数有什么问题?当然,这样的构造函数也可以被工厂细读。