【问题标题】:What's the point of deleting default class constructor?删除默认类构造函数有什么意义?
【发布时间】:2018-07-17 19:00:26
【问题描述】:

我正在准备我的 CPP 考试,其中一个问题是:您可以删除默认类构造函数吗?如果可以,这样做的原因是什么?好的,显然你可以做到:

class MyClass 
{ 
  public: 
    MyClass() = delete; 
};

但我不明白你为什么要这样做?

【问题讨论】:

  • @DerekJohnson:这个呢:stackoverflow.com/q/13654927/27678
  • @acraig5075 如果你提供另一个构造函数,那么默认构造函数不会生成,所以不需要删除它。
  • @AndyG 老实说,如果您仔细阅读此内容,它实际上并没有回答这个问题。来自某人的评论:“老实说,我不明白这是如何回答主要问题的。标题中的问题和 OP 在帖子中的第一个问题是:我何时/为什么要显式删除我的构造函数?”
  • @acraig5075 你不应该在评论区回答问题。

标签: c++ default-constructor


【解决方案1】:

考虑以下类:

struct Foo {
    int i;
};

这个类是一个聚合,你可以创建一个包含所有这三个定义的实例:

int main() {
    Foo f1;     // i uninitialized
    Foo f2{};   // i initialized to zero
    Foo f3{42}; // i initialized to 42
}

现在,假设您不喜欢未初始化的值以及它们可能产生的未定义行为。可以删除Foo的默认构造函数:

struct Foo {
    Foo() = delete;
    int i;
};

Foo 仍然是一个聚合,但只有后两个定义有效——第一个现在是编译时错误。

【讨论】:

  • 或者,直接使用struct Foo { int i = 0; };
  • @T.C.是的,但我提出这个例子是最小的,可能有更复杂的情况可以派上用场。不过,我自己也想不出。
  • @T.C. Foo 不再是聚合;这本身不是一个发行者,但我们宁愿明确它。 (注:仅适用于 C++11 和 C++14)
  • @YSC 仅适用于 C++11,你的意思是。
  • @T.C.何我在我的pdf中搞混了。是的,你是对的,只有 C++11。
【解决方案2】:

删除默认构造函数有几个原因。

  1. 该类是纯静态的,您不希望用户仅使用静态方法/成员来实例化一个类。这种类的一个示例可能是仅使用静态方法来实现工厂设计模式来创建新类。
  2. 类具有默认构造函数是没有意义的(因为它需要参数/没有对类有意义的默认值)。在这种情况下,= delete 是一种风格,正如@HolyBlackCat 所说,但它确实通过告诉客户端代码使用参数调用构造函数来阐明您的意图。
  3. 您不希望聚合类的数据未初始化。

如果第二个陈述不清楚,请考虑以下示例:

class A
{
public:
   //A() = delete; 
   A(int, int) {};
};

如果您现在尝试调用默认构造函数,您会收到类似于 (GCC 7.2) 的错误:

错误:没有匹配的函数调用 'A::A()'

但是,如果您取消注释带有 = delete 的行,那么您将获得以下信息:

错误:使用已删除的函数'A::A()'

这清楚地表明,与另一个错误相比,一个人正在尝试使用已删除的构造函数,这有点不清楚。

【讨论】:

  • 在第二种情况下它会被自动删除,所以= delete 将是一个风格的东西。
  • @Quentin 可能是一个只有静态成员的类模板。
  • @aschepler 很公平。不过命名空间模板会很酷。
  • @HolyBlackCat 不……它会未声明,而不是删除。一个微妙但有时很重要的区别。实际上,尝试使用前者会导致“No matching constructor in call...”之类的错误,而后者会导致“Default constructor is deleted in call ...”之类的错误(我懒得检查确切的不过,这取决于编译器。)
  • @HolyBlackCat 已删除的功能。参与重载决议。例如。使用X(const X&) user-declared,没有隐式声明 move c'tor,但 X(std::move(anotherX)) 仍然可以工作,选择 copy c'tor 作为最接近的匹配。但是如果移动 c'tor 被删除,这段代码就会变得不正确。此外,如果你有一个可变参数 c'tor 例如X(Args&&...),这可用于构造不带参数的对象,但如果有已删除的 X(),则不能。 reference
【解决方案3】:

有时类并不打算被实例化。

到目前为止尚未提及的一个示例是“特征”类。 比如std::char_traits,虽然标准没有说它的默认构造函数需要删除,但是它的默认构造函数用处不大,因为类本身是空的,它的所有函数都是静态的,不需要被实例化以使用它提供的类型别名。

Trait 类通常只用于支持其他类(通常是其他模板类),因此删除它们的默认构造函数通常是有意义的 - 以强化它们只是辅助类型而不真正应该这样做的概念像对象一样使用。

【讨论】:

    【解决方案4】:

    多个默认选择

    当默认或未初始化状态有多种选择时,删除类的默认构造函数是个好主意。例如,假设我有一个班级,

    template<typename F>
    class Polynomial;
    

    表示字段上的多项式,F。在这种情况下,多项式的默认值有很多选择。一个可能是加法下多项式的恒等式,即零,但我们也可以有乘法恒等式,统一。这取决于用户打算如何推理该类以及如何使用它。


    无默认选项

    另一个值得注意的情况是,我们没有多个可能有意义的默认状态,而是没有。例如,假设我们有一个表示流形或表面的类。

    那么Manifold() 是什么?这是一个空旷的空间,什么都没有,没有表面,没有距离或度量的概念。但是,将其视为流形是没有意义的,而应该是更一般的东西,例如拓扑空间。

    所以,在这种情况下,我也会选择删除默认构造函数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-02-24
      • 2019-05-07
      • 1970-01-01
      • 1970-01-01
      • 2022-01-03
      • 1970-01-01
      • 2018-07-01
      相关资源
      最近更新 更多