在静态函数中返回对象而不是构建对象的好处是什么?

时间:2019-02-21 10:43:42

标签: c++ constructor static-methods

以以下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都做出了这种选择,但我不明白这样做的好处是什么,以及为什么缺少该构造函数。

2 个答案:

答案 0 :(得分:1)

静态创建方法很方便,因为它们不需要创建冗余对象,并且可以将其添加到其创建的对象的代码中。使用创建方法insteed构造函数的原因很多。这里只是一些:

  1. 构造函数必须始终以有效的对象创建完成。在构造函数中使用异常是非常糟糕的做法。如果无法创建对象,例如由于参数不正确或初始化顺序不正确,该怎么办?对于创建方法,您可以简单地返回nullptr或某些“错误”的对象类型。

  2. 如果我们要自定义对象创建而不更改其代码。例如,我们要构建一个对象并对其进行配置,或者我们没有可用参数的构造函数。包装函数使您无需触摸类代码即可解决问题。这适用于给定的示例as you can seefromString在构造函数调用之前解析字符串参数。

  3. 我们不知道要构造什么样的对象。这是在运行时决定的。通常,我们可以返回基础对象,并在包装​​器内选择必要的类。这使您无需更改用于选择具体对象的主要代码。

  4. 我们要控制所有对象的创建,以消除可能的内存泄漏。例如,在取消初始化库时,即使用户忘记这样做,也要释放所有资源。

我建议您熟悉设计模式,尤其是с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);
}

当然有可能,推迟到一个带有特殊功能对象的私有构造函数。但是该库的作者可能认为这太神秘或难以维护。