Is it good practice to have a class constructor that uses default parameters, or should I use separate overloaded constructors? For example:
// Use this...
class foo
{
private:
std::string name_;
unsigned int age_;
public:
foo(const std::string& name = "", const unsigned int age = 0) :
name_(name),
age_(age)
{
...
}
};
// Or this?
class foo
{
private:
std::string name_;
unsigned int age_;
public:
foo() :
name_(""),
age_(0)
{
}
foo(const std::string& name, const unsigned int age) :
name_(name),
age_(age)
{
...
}
};
Either version seems to work, e.g.:
foo f1;
foo f2("Name", 30);
Which style do you prefer or recommend and why?
Mostly personal choice. However, overload can do anything default parameter can do, but not vice versa.
Example:
You can use overload to write A(int x, foo& a) and A(int x), but you cannot use default parameter to write A(int x, foo& = null).
The general rule is to use whatever makes sense and makes the code more readable.
This discussion apply both to constructors, but also methods and functions.
Using default parameters?
The good thing is that you won't need to overload constructors/methods/functions for each case:
The bad thing is that you must declare your default in the header, so you have an hidden dependancy: Like when you change the code of an inlined function, if you change the default value in your header, you'll need to recompile all sources using this header to be sure they will use the new default.
If you don't, the sources will still use the old default value.
using overloaded constructors/methods/functions?
The good thing is that if your functions are not inlined, you then control the default value in the source by choosing how one function will behave. For example:
The problem is that you have to maintain multiple constructors/methods/functions, and their forwardings.
Definitely a matter of style. I prefer constructors with default parameters, so long as the parameters make sense. Classes in the standard use them as well, which speaks in their favor.
One thing to watch out for is if you have defaults for all but one parameter, your class can be implicitly converted from that parameter type. Check out this thread for more info.
I would go with the default parameters, for this reason: Your example assumes that ctor parameters directly correspond to member variables. But what if that is not the case, and you have to process the parameters before the object is initialize. Having one common ctor would be the best way to go.
I'd go with the default arguments, especially since C++ doesn't let you chain constructors (so you end up having to duplicate the initialiser list, and possibly more, for each overload).
That said, there are some gotchas with default arguments, including the fact that constants may be inlined (and thereby become part of your class' binary interface). Another to watch out for is that adding default arguments can turn an explicit multi-argument constructor into an implicit one-argument constructor:
In my experience, default parameters seem cool at the time and make my laziness factor happy, but then down the road I'm using the class and I am surprised when the default kicks in. So I don't really think it's a good idea; better to have a className::className() and then a className::init(arglist). Just for that maintainability edge.