【问题标题】:Implementing a default constructor实现默认构造函数
【发布时间】:2009-11-06 21:43:32
【问题描述】:

我正在尝试在 C++ 中实现一个 DateTime 类:

class DateTime {
public:
    DateTime();
    DateTime(time_t ticks);
    DateTime(int day, int month, int year);
    DateTime(int day, int month, int year, int hour, int minute, int second);
    //...

private:
    time_t ticks;
    int day;
    int month;
    //...
}

然后在应用中:

DateTime date1; //default constructor

我知道c++需要有一个默认的构造函数,但是在这种情况下我应该如何实现呢?

是否应该将所有属性设置为 0?这将使所有其他方法都有效,但看起来并不直观......

是否应该只保留所有属性未初始化?这将使它的任何方法都不起作用,但它似乎比 0 更直观,因为你还没有对它做任何事情。

是否应该设置一个内部bool initialized=false,然后所有方法在对其进行操作之前对其进行检查?

我不太确定这一点。有没有“标准”的做法?

【问题讨论】:

    标签: c++ constructor implementation


    【解决方案1】:

    通常,默认构造函数会将您初始化为“默认”参考时间。

    如果您在内部使用 time_t,将其设置为 0 的 time_tUnix epoch,即 1970 年 1 月 1 日)将是一个合理的选择,因为“0”值是常见的默认值。

    话虽如此,C++ 中不需要默认构造函数 - 您可以拥有一个没有默认构造函数的类型,这需要指定一个有效的“时间”。

    【讨论】:

      【解决方案2】:

      默认 ctor 不是 C++ 要求的。如果您不知道它应该如何工作,那么您很可能不应该拥有它。如果您要拥有一个,最明显的做法可能是检索当前日期和时间。

      编辑:如果您没有明确定义任何 ctor,那么编译器将为您生成一个默认 ctor 和一个复制 ctor。两者都不一定是一件特别糟糕的事情——如果你不确定你的数据应该如何初始化,那可能是完全合理的。

      就创建向量而言:不,您不必拥有默认 ctor 即可将事物放入向量中。通常,默认 ctor 用于初始化尚未分配任何值的项目。例如,std::vector<DateTime> x(10); 创建一个包含 10 个 DateTime 对象的向量,每个对象都使用默认 ctor 进行初始化。如果您没有(也不想要)默认 ctor,则可以传递 DateTime 的实例以用于初始化这些对象:

      DateTime party_time(12, 31, 1999);
      std::vector<DateTime> x(10, party_time);
      

      【讨论】:

      • 嗯,按照我的理解,如果我不指定默认值,编译器会为我创建一个,我理解这主要是一件坏事。
      • 但在某些情况下需要默认构造函数。例如,如果你想要一个 DateTime 对象的向量。
      • 或者只有在没有声明其他构造函数的情况下,默认与否?
      • @Austin Hyde:不,如果您定义自己的构造函数,编译器将不会提供默认构造函数。
      • @Austin:如果您不创建任何构造函数,编译器将创建一个默认构造函数 - 但如果您创建一个,它将不会生成默认构造函数。
      【解决方案3】:

      如果你不想要默认构造函数,你可以声明一个私有的默认构造函数,这样它就不能被使用了。

      【讨论】:

      • 除非你定义了任何构造函数,编译器不会生成默认值。因此,这仅在您不需要构造函数时才有用。我无法想象你为什么要这样做。但是,该技术很有用,它可以通过复制构造函数和复制赋值运算符来强制对象不可复制。
      • @Fred Larson:将构造函数设为私有是用于创建单例和静态工厂方法的主要技术。
      【解决方案4】:

      拥有一个默认构造函数是可选的,但在某些情况下它通常可以更轻松地使用您的类。如果您不提供 任何 构造函数,那么编译器将为您生成一个默认构造函数,该构造函数等效于具有空初始化列表和空函数体的构造函数。

      在实现默认构造函数时,通常最好使其尽可能高效,因为默认构造函数不被使用或覆盖。例如。流式传输:T t; std::cin &gt;&gt; t; 或创建一个固定的事物数组以便稍后重新分配 T arr[100];。出于这个原因,虽然让默认构造函数将DateTime 设置为“现在”似乎很明显,但如果这涉及系统调用或其他昂贵的操作来找出当前日期,通常最好不要这样做默认构造函数。

      如果你根本没有构造函数,那么在很多情况下,值初始化会导致你的所有成员在任何情况下都被初始化,例如:

      // Explicit value-initialzation of dynamcially allocated DateTime
      DateTime* pdt = new DateTime();
      
      // Value-initialized temporary
      FunctionTakesDateTime( DateTime() );
      
      // Copy-initalization from a value-initialized temporary
      DateTime dt = DateTime();
      

      如果您提供了默认构造函数,但没有显式初始化类的所有成员,并且这些成员属于 POD 类型(如 time_tint),那么这些成员现在将保持未初始化状态。要获得与没有用户声明的构造函数一样的值初始化效果,您必须在默认构造函数中显式初始化所有成员。

      DateTime() : ticks(), days(), months() /*, ... */ {}
      

      这将是我首选的默认构造函数实现。这意味着默认构造仍然相当便宜,但默认构造 DateTimes 仍然具有明确定义且易于识别的值,用于调试和诊断目的。

      虽然您可以使用 initialized 布尔值,允许您进行“延迟构造”,但我不建议您这样做。它为所有其他类设计增加了很多开销,而收益可能很小。如果客户端想要使用非默认值操作DateTime,则应由客户端根据需要对其进行初始化。

      【讨论】:

        猜你喜欢
        • 2012-06-22
        • 2013-10-27
        • 2012-02-15
        • 2016-07-23
        • 1970-01-01
        • 2023-03-20
        • 2021-06-16
        • 1970-01-01
        • 2010-10-30
        相关资源
        最近更新 更多