以以下Qt Framework文档为例,即使我的问题不是特定于Qt的:
https://doc.qt.io/qt-5/qversionnumber.html
您可以找到静态公共成员函数:
QVersionNumber fromString(const QString &string, int *suffixIndex = nullptr)
代替:
QVersionNumber(const QString &string, int *suffixIndex = nullptr)
在构造函数列表中。
我已经看到许多库API都做出了这种选择,但我不明白这样做的好处是什么,以及为什么缺少该构造函数。
答案 0 :(得分:1)
静态创建方法很方便,因为它们不需要创建冗余对象,并且可以将其添加到其创建的对象的代码中。使用创建方法insteed构造函数的原因很多。这里只是一些:
构造函数必须始终以有效的对象创建完成。在构造函数中使用异常是非常糟糕的做法。如果无法创建对象,例如由于参数不正确或初始化顺序不正确,该怎么办?对于创建方法,您可以简单地返回nullptr
或某些“错误”的对象类型。
如果我们要自定义对象创建而不更改其代码。例如,我们要构建一个对象并对其进行配置,或者我们没有可用参数的构造函数。包装函数使您无需触摸类代码即可解决问题。这适用于给定的示例as you can see,fromString
在构造函数调用之前解析字符串参数。
我们不知道要构造什么样的对象。这是在运行时决定的。通常,我们可以返回基础对象,并在包装器内选择必要的类。这使您无需更改用于选择具体对象的主要代码。
我们要控制所有对象的创建,以消除可能的内存泄漏。例如,在取消初始化库时,即使用户忘记这样做,也要释放所有资源。
我建议您熟悉设计模式,尤其是сreational pattern。
答案 1 :(得分:1)
这实际上是一个很好的问题。
原因因情况而异,但涉及以下问题:
以上所有内容都会涉及一定程度的主观性。
一个假设的例子,猜测一个QVersionNumber的内部,
您如何将其写在初始化列表中?
QVersionNumber
QVersionNumber::fromString(const QString &string, int *suffixIndex)
{
std::optional<QVersionNumber> result;
auto first = string.begin();
auto last = string.end();
auto opt_major = maybe_extract_decimal(first, last); // modifies first
if (not opt_major.has_value())
result.emplace();
else
{
auto opt_minor = maybe_extract_decimal(first, last); // modifies first
if (not opt_major.has_value())
result.emplace(*opt_major);
else
result.emplace(*opt_minor);
}
if (suffixIndex)
*suffixIndex = int(std::difference(string.begin(), first);
return *std::move(result);
}
当然有可能,推迟到一个带有特殊功能对象的私有构造函数。但是该库的作者可能认为这太神秘或难以维护。