代码之家  ›  专栏  ›  技术社区  ›  ABCplus

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

  •  2
  • ABCplus  · 技术社区  · 7 年前

    以Qt框架的以下文档为例,即使我的问题不是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 回复  |  直到 7 年前
        1
  •  1
  •   Richard Hodges    7 年前

    这实际上是个很好的问题。

    原因因情况而异,但涉及以下问题:

    • 构造器的可读性如何?
    • 我是在创建人工对象还是不必要地复制条件语句,以便用初始化器列表来编写构造函数?
    • 我的构造器是否与要执行不同类型构造的构造器有歧义?
    • 很明显我的构造器不需要在代码中拼出名字就可以了吗?

    所有这些都会涉及到一定程度的主观性。

    假设的例子,猜测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);
    }
    

    这当然是可能的,遵从一个私有构造函数,它接受一个特殊的函数对象。但图书馆的作者可能认为这太过神秘或难以维护。

        2
  •  1
  •   Dmytro Dadyka    7 年前

    静态创建方法不需要创建多余的对象,并且可以添加到所创建对象的代码中,因此非常方便,使用creational method代替eed constructor有很多原因。以下是一些:

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

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

    3. 我们不知道要构造什么样的对象。这是在运行时决定的。一般来说,我们可以返回基对象,并在包装器中选择必要的类。这允许您不更改具体对象选择的主代码。

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

    我建议您熟悉设计模式,特别是 сreational pattern .