views:

220

answers:

4

I am trying to implement a DateTime class in C++:

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;
    //...
}

then in application:

DateTime date1; //default constructor

I know that having a default constructor is required for c++, but how should I implement it in this situation?

Should it set all properties to 0? That would make all other methods work, but doesn't really seem intuitive...

Should it just leave all properties un-initialized? That would make none of its methods work, but it seems more intuitive than 0, because you haven't done anything to it yet.

Should it set an internal bool initialized=false then all methods check that before operating on it?

I'm not really sure on this one. Is there a "standard" way of doing it?

+9  A: 

Typically, the default constructor would initialize you to a "default" reference time.

If you're using a time_t internally, setting it to time_t of 0 (Unix epoch, which is 1/1/1970) would be a reasonable option, since "0" values are common defaults.

That being said, a default constructor is not required in C++ - you can have a type with no default constructor, which would require a valid "time" to be specified.

Reed Copsey
+8  A: 

A default ctor is not required by C++. If you don't have a good idea how it should work, chances are pretty good that you just shouldn't have one. If you were going to have one, the most obvious thing to do would probably be to retrieve the current date and time.

Edit: If you don't explicitly define any ctors, then the compiler will generate a default ctor and a copy ctor for you. Neither is necessarily a particularly bad thing at all -- if you're not sure how your data should be initialized, it may be perfectly reasonable.

As far as creating a vector goes: no, you do not have to have a default ctor to put things in a vector. Normally a default ctor is used to initialize items that haven't had any value assigned to them. E.g., std::vector<DateTime> x(10); creates a vector of 10 DateTime objects, each initialized with the default ctor. If you don't have (and don't want) a default ctor, you can pass an instance of DateTime to be used to initialize those objects instead:

DateTime party_time(12, 31, 1999);
std::vector<DateTime> x(10, party_time);
Jerry Coffin
Well, the way I understand it, if I don't specify a default, the compiler creates one for me, which I understand to mostly be a bad thing.
Austin Hyde
In some cases a default constructor is required, though. For instance, if you want to have a vector of DateTime objects.
Fred Larson
Or is that only if there is no other constructors declared, default or not?
Austin Hyde
@Austin Hyde: No, if you define your own constructors, the compiler will not provide a default constructor.
Fred Larson
@Austin: The compiler will create a default constructor if you don't create ANY constructors - but if you make one, it will not generate a default constructor.
Reed Copsey
Thanks guys, that makes more sense. But what happens when I do `DateTime date;` with out calling a constructor?
Austin Hyde
@Austin: Writing `DateTime date;` invokes `DateTime`'s default ctor. So if it does not have one, it fails to compile.
Éric Malenfant
@Fred: Even when used as a vector element, a default constructor is not necessary, as long as you provide default values to resize() and the constructor. For example: Assuming that Foo does not have a default ctor, and has an explicit ctor taking an int, and v is a `vector<Foo>`, this `v.resize(3);` does not compile, but this does: `v.resize(3, Foo(1));`
Éric Malenfant
+1  A: 

If you don't want a default constructor, you can declare a private default constructor such that it can't be used.

Corey Porter
Except that if you define any constructors, the compiler doesn't generate a default. So this is only useful if you want no constructors. I can't imagine why you would want to do that. The technique is useful, however, with copy constructors and copy assignment operators to force an object to be non-copyable.
Fred Larson
+1  A: 

Having a default constructor is optional, but it often makes use of your class easier in some situations. If you don't provide any constructors, then the compiler will generate a default constructor for you which is equivalent to one with an empty initializer list and an empty function body.

When implementing a default constructor, it's usually best to make it as efficient as possible as frequently of default constructor is not used or overwritten. E.g. Streaming: T t; std::cin >> t; or creating a fixed array of things to be re-assigned later T arr[100];. For this reason, while it might seem obvious to make the default constructor set a DateTime to "now", if this involves a system call or other expensive operation to find out the current date it is usually better not to do this for a default constructor.

If you had no constructors at all, then there are many situations where value-initialization would cause all your members to be initialized in any case, e.g.:

// 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();

If you supplied a default constructor but didn't explicitly initialize all the members of the class and those members were of POD-type (like time_t and int) then those members would now be left uninitialized. To get the same effect for value-initialization as if you had no user-declared constructors you would have to explicitly initialize all your members in your default constructor.

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

This would be my preferred default constructor implementation. It means that default construction is still fairly cheap, but default constucted DateTimes still have a well defined and easily recognizable value for debugging and diagnostic purposes.

While you can have an initialized boolean, allowing you to have "delayed construction", I wouldn't recommend it. It adds a lot of overhead to all the rest of the class design with what would probably be very little gain. If a client wants to manipulate DateTime with non-default values then it should be up to the client to initialize them as required.

Charles Bailey