在静态函数中返回一个对象而不是构建它有什么好处?
What is the advantage of returning an object in a static function instead of building it?
以 Qt 框架的以下文档为例,即使我的问题不是特定于 Qt 的:
https://doc.qt.io/qt-5/qversionnumber.html
你可以找到静态public成员函数:
QVersionNumber fromString(const QString &string, int *suffixIndex = nullptr)
而不是:
QVersionNumber(const QString &string, int *suffixIndex = nullptr)
在构造函数列表中。
我在许多库中都看到过这种选择 API 但我不明白它的优势是什么以及为什么缺少该构造函数。
静态创建方法很方便,因为它们不需要创建冗余对象,并且可以添加到对象的代码中,creates.There 有很多理由使用创建方法代替构造函数。这里只是一些:
构造函数必须始终与有效对象创建一起完成。在构造函数中使用异常是一种非常糟糕的做法。如果无法创建对象,例如由于不正确的参数或不正确的初始化顺序,我们该怎么办?在创建方法的情况下,您可以简单地 return nullptr
或一些 "wrong" 对象类型。
如果我们想在不更改其代码的情况下自定义对象创建。例如,我们想要构建一个对象并对其进行配置,或者我们没有可用参数的构造函数。包装函数可以让你在不触及 class 代码的情况下解决问题。这适用于给定的示例,as you can see,fromString
在构造函数调用之前解析字符串参数。
我们不知道构造什么样的对象。这是在 运行 时决定的。一般来说,我们可以return base object,在wrapper里面选择必要的class。这允许您不更改具体对象选择的主要代码。
我们要控制所有对象的创建以消除可能的内存泄漏。例如,当取消初始化库时,释放所有资源,即使用户忘记这样做。
我建议您熟悉设计模式,尤其是 сreational pattern。
这实际上是一个很好的问题。
原因因情况而异,但涉及以下问题:
- 构造函数的可读性如何?
- 我是在创建人造对象还是不必要地复制条件,以便根据初始化列表编写构造函数?
- 我的构造函数是否与旨在执行不同类型构造的构造函数有歧义?
- 我的构造函数在做什么而不用在代码中拼出名字就很明显了吗?
以上所有内容都具有一定程度的主观性。
假设示例,猜测 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);
}
这当然是可能的,推迟到采用专用函数对象的私有构造函数。但是库的作者可能认为这太神秘或难以维护。
以 Qt 框架的以下文档为例,即使我的问题不是特定于 Qt 的:
https://doc.qt.io/qt-5/qversionnumber.html
你可以找到静态public成员函数:
QVersionNumber fromString(const QString &string, int *suffixIndex = nullptr)
而不是:
QVersionNumber(const QString &string, int *suffixIndex = nullptr)
在构造函数列表中。
我在许多库中都看到过这种选择 API 但我不明白它的优势是什么以及为什么缺少该构造函数。
静态创建方法很方便,因为它们不需要创建冗余对象,并且可以添加到对象的代码中,creates.There 有很多理由使用创建方法代替构造函数。这里只是一些:
构造函数必须始终与有效对象创建一起完成。在构造函数中使用异常是一种非常糟糕的做法。如果无法创建对象,例如由于不正确的参数或不正确的初始化顺序,我们该怎么办?在创建方法的情况下,您可以简单地 return
nullptr
或一些 "wrong" 对象类型。如果我们想在不更改其代码的情况下自定义对象创建。例如,我们想要构建一个对象并对其进行配置,或者我们没有可用参数的构造函数。包装函数可以让你在不触及 class 代码的情况下解决问题。这适用于给定的示例,as you can see,
fromString
在构造函数调用之前解析字符串参数。我们不知道构造什么样的对象。这是在 运行 时决定的。一般来说,我们可以return base object,在wrapper里面选择必要的class。这允许您不更改具体对象选择的主要代码。
我们要控制所有对象的创建以消除可能的内存泄漏。例如,当取消初始化库时,释放所有资源,即使用户忘记这样做。
我建议您熟悉设计模式,尤其是 сreational pattern。
这实际上是一个很好的问题。
原因因情况而异,但涉及以下问题:
- 构造函数的可读性如何?
- 我是在创建人造对象还是不必要地复制条件,以便根据初始化列表编写构造函数?
- 我的构造函数是否与旨在执行不同类型构造的构造函数有歧义?
- 我的构造函数在做什么而不用在代码中拼出名字就很明显了吗?
以上所有内容都具有一定程度的主观性。
假设示例,猜测 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);
}
这当然是可能的,推迟到采用专用函数对象的私有构造函数。但是库的作者可能认为这太神秘或难以维护。