Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
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?
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'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:
class Vehicle {
public:
Vehicle(int wheels, std::string name = "Mini");
};
Vehicle x = 5; // this compiles just fine... did you really want it to?
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:
// Header
void doSomething(int i = 25) ;
// Source
void doSomething(int i)
{
// Do something with i
}
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:
// Header
void doSomething() ;
void doSomething(int i) ;
// Source
void doSomething()
{
doSomething(25) ;
}
void doSomething(int i)
{
// Do something with i
}
The problem is that you have to maintain multiple constructors/methods/functions, and their forwardings.
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.
Sam's answer gives the reason that default arguments are preferable for constructors rather than overloading. I just want to add that C++-0x will allow delegation from one constructor to another, thereby removing the need for defaults.
Either approach works. But if you have a long list of optional parameters make a default constructor and then have your set function return a reference to this. Then chain the settors.
class Thingy2
{
public:
enum Color{red,gree,blue};
Thingy2();
Thingy2 & color(Color);
Color color()const;
Thingy2 & length(double);
double length()const;
Thingy2 & width(double);
double width()const;
Thingy2 & height(double);
double height()const;
Thingy2 & rotationX(double);
double rotationX()const;
Thingy2 & rotatationY(double);
double rotatationY()const;
Thingy2 & rotationZ(double);
double rotationZ()const;
}
main()
{
// gets default rotations
Thingy2 * foo=new Thingy2().color(ret)
.length(1).width(4).height(9)
// gets default color and sizes
Thingy2 * bar=new Thingy2()
.rotationX(0.0).rotationY(PI),rotationZ(0.5*PI);
// everything specified.
Thingy2 * thing=new Thingy2().color(ret)
.length(1).width(4).height(9)
.rotationX(0.0).rotationY(PI),rotationZ(0.5*PI);
}
Now when constructing the objects you can pick an choose which properties to override and which ones you have set are explicitly named. Much more readable :)
Also, you no longer have to remember the order of the arguments to the constructor.
One more thing to consider is whether or not the class could be used in an array:
foo bar[400];
In this scenario, there is no advantage to using the default parameter.
This would certainly NOT work:
foo bar("david", 34)[400]; // NOPE
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.
If creating constructors with arguments is bad (as many would argue), then making them with default arguments is even worse. I've recently started to come around to the opinion that ctor arguments are bad, because your ctor logic should be as minimal as possible. How do you deal with error handling in the ctor, should somebody pass in an argument that doesn't make any sense? You can either throw an exception, which is bad news unless all of your callers are prepared to wrap any "new" calls inside of try blocks, or setting some "is-initialized" member variable, which is kind of a dirty hack.
Therefore, the only way to make sure that the arguments passed into the initialization stage of your object is to set up a separate initialize() method where you can check the return code.
The use of default arguments is bad for two reasons; first of all, if you want to add another argument to the ctor, then you are stuck putting it at the beginning and changing the entire API. Furthermore, most programmers are accustomed to figuring out an API by the way that it's used in practice -- this is especially true for non-public API's used inside of an organization where formal documentation may not exist. When other programmers see that the majority of the calls don't contain any arguments, they will do the same, remaining blissfully unaware of the default behavior your default arguments impose on them.
Also, it's worth noting that the google C++ style guide shuns both ctor arguments (unless absolutely necessary), and default arguments to functions or methods.
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.
One thing bothering me with default parameters is that you can't specify the last parameters but use the default values for the first ones. For example, in your code, you can't create a Foo with no name but a given age (however, if I remember correctly, this will be possible in C++0x, with the unified constructing syntax). Sometimes, this makes sense, but it can also be really awkward.
In my opinion, there is no rule of thumb. Personnaly, I tend to use multiple overloaded constructors (or methods), except if only the last argument needs a default value.
Matter of style, but as Matt said, definitely consider marking constructors with default arguments which would allow implicit conversion as 'explicit' to avoid unintended automatic conversion. It's not a requirement (and may not be preferable if you're making a wrapper class which you want to implicitly convert to), but it can prevent errors.
I personally like defaults when appropriate, because I dislike repeated code. YMMV.
Related
I understood 'explicit' concept related to constructors in C++ which will take single parameter as input. But I read on some websites that we need to change the constructor to explicit, irrespective of the number of parameters the constructor will take as input.
Can any one please help me to understand below issues.
Why do we need to make a constructor as explicit if it doesn't take any input?
What is the use of making a constructor as explicit if it takes more than one parameter and all the parameters are not default?
Why do we need to make a constructor as explicit if it doesn't take any input?
That seems incorrect to me. A constructor needs to be explicit if you don't want the constructor to be called automatically.
Say you have:
struct Foo
{
Foo() {}
Foo(int) {}
};
void bar(Foo)
{
}
Then,
bar(1);
will work. It is translated as:
bar(Foo(1));
If there is a default constructor, i.e. one that does not take any arguments, there is nothing to convert from. You may not use:
bar();
and hope to get it translated as:
bar(Foo{});
What is the use of making a constructor as explicit if it takes more than one parameter and all the parameters are not default?
This one has some validity.
If you had:
struct Foo
{
Foo() {}
Foo(int, int) {}
};
void bar(Foo)
{
}
You may not use
bar(10, 20);
or
bar((10, 20));
and hope to have it translated as:
bar(Foo(10, 20));
However, you may use:
bar({10, 20});
and it will be translated as:
bar(Foo{10, 20});
If you want to prevent use of this syntax, bar({10, 20}), you may make the constructor explicit. IMO, this has less utility. The potential for inadvertently misusing a constructor with one argument is real. The potential for inadvertently misusing a constructor with more than one argument is very small.
Just to complement #R Sahu's answer from a different perspective:
The recommendation to use explicit for every constructor irrespective of how many arguments it takes can steam from the fact that strictly speaking every C++ constructor should be explicit by default and instead we would use implicit keyword: why constructors aren't explicit by default?
I saw this problem so many times: initially a class has a default constructor. Then after a while it's modified and a parameter is added. It's very easy to forget to add explicit in this case.
It's even easier to forget to add explicit when you remove a parameter from a two-arguments constructor. Also often your initial explicit one-parameter constructor got additional parameters or lost its parameter but explicit was left by mistake and compiler doesn't complain about this.
After a while your code starts to look like a christmas tree with many constructors that should be explicit but are not and others that are but shouldn't.
I suppose it's the reason why the website you mentioned recommends to use explicit always.
Let's say I have a class:
class C{
int x_;
int y_;
public:
C(int x, int y): x_(x), y_(y){}
};
Then I want to add construction from a string, which would just parse x and y. Before reading Meyers's book I would usually make it another constructor in class C. However, it's also possible to make it non-member non-friend:
C CFromString(const std::string& s){
int x, y;
//...parse them somehow, throw exception if needed...
return C(x,y);
}
To me this is standard situation for many "value classes", when there is a "main" constructor which sets private members to provided values (probably checking there correctness). Other constructors for such classes are often just calculate these values from some other arguments.
Are there any drawbacks in making such constructors non-member non-friends like in my example?
Upd. I understand the Meyers's advice, and what are the advantages of NMNF functions. There is just no examples of NMNF object construction in his book, so I want to ensure that his advice applies to construction as well.
If you start adding constructors for every possible way a class can be serialized, you are tightly coupling that class with those serialization methods.
It is preferred that you separate the class and the serializer in order to separate concerns. Let the class focus on what the class does and the serializer on what it does (read json or whatever)
You have to consider that your class might be serialized from a file, from a socket, from json, from xml, from a database...from any number of things.
That's why in modern programming we use interfaces.
We also make use of the Factory pattern.
One drawback is a bit of inconsistency, which is an esthetic concern.
You're calling a CFromString constructor function rather than invoking a constructor called C. The relationship between them is arbitrary, just through the C prefix in the name.
If you make it a static member function, then you can call it C::FromString so that it belongs to the class.
If this is done all over the place in a large project, some sort of convention would help. Like say, whenever we have a class C, and a non-member constructor function for making C-s, let's always call it CCons, and then always use overloading for different types. Thus, if we have a Widget class, we then call our overloaded family WidgetCons:
Widget WidgetCons(const std::string &s) { /* make it from string */ }
Widget WidgetCons(int i) { /* make it from int */ }
and so on. If this is consistent in our 250,000 line codebase, whenever someone sees any FooCons or BarCons, they know exactly what it is.
If I have a class:
class className{
int i;
public:
className(int value);
};
What is considered as the best practise for initializing the class variable 'i' from the constructor as per the below choices?
1) Use the actual field name with an underscore:
className::className(int i_){
i = i_;
}
2) Use the actual field name with "this":
className::className(int i){
this->i = i;
}
3) Completely inconsistent things like:
className::className(int value){
i = value;
}
I have seen this question being directly addressed for Java but not so much for C++. I ask because I would favor number 2 as I would personally prefer less variable names being made. However I would like to know what further considerations this could mean for the compiler or linker etc. I would also like to stick with the C++ norm.
Many Thanks!
Yes that's ok.
Some people actually think it idiomatic.
However, your samples all lack the use of initializer lists :)
class className{
int i;
public:
className(int value) : i(value) {};
};
I suggest to avoid the confusion with duplicate names. It makes the compiler complain if you accidentally mess up.
The best practice is to initialize your member variables in the initializer list:
className::className(int i_) : i(i_){}
^^^^^
Reasons:
Performance: You avoid unnecessary calls to members' default constructors.
Having Members not default constructible: If you have member variables that aren't default constructible (i.e., they don't have a default constructor), you are obliged to initialize them in the initializer list.
Having Members const-qualified: Same as 2.
Having Members references to objects: Same as 2.
Readability: Opinion based.
Extensibility: Opinion based.
As far as it concerns the naming issue: IMHO, it's primarily opinion based. Personally, for parameters of a constructor I use the suffix underscore as well.
I am in agreement with #sehe, to clarify on his context of initializer lists:
className::className(int i_) : i(i_) {}
However! I think the identifier names are backwards in terms of appropriateness. i_ should be the private member variable, and i should be the constructor parameter.
My notes on each "choice":
1) It's easy to see which parameters correspond with one another here
2) It's explicitness here
3) I think you've already concluded your opinion on this one by wording it 'Completely Inconsistent' :).
I have two options. Either make a class that accepts a lot arguments in its constructors, or create a lot of setter methods and an init method. I'm not sure which is preferred option, should some arguments be accepted in constructors, while others could be manually set via setter? Or am I over-thinking this?
This is a relevant question, also by me: Conflicts between member names and constructor argument names.
If after you create an object you have to call set or init to actually use it... well, that's just an awful design.
If the object is usable without some of the members initialized the way you want them to be, you can set them later on.
The golden rule here is - if you create an object, you should be able to use it without doing any other sort of initialization.
Expanding on the answer:
Say you have a shape with 10 sides, 10 corners, a color and a name, that can be connected to a different shape. The constructor should look like:
MyShape(Point c1, Point c2,...., Point c10, Color c, Name n)
As you can see, I've omitted the connected shape because it can sensibly be set to NULL if the current object is not connected. However, in the absence of any of the other parameters, the object isn't valid, so they should be set in the constructor.
A possible overload (alternitively a default argument) can be:
MyShape(Point c1, Point c2,...., Point c10, Color c, Name n,
MyShape* connectedShape /*=NULL*/)
You should provide the constructor arguments for all the members which are necessary to preserve the class invariant. In other words, object should be in valid and consistent state from the moment it is created until it is destroyed. Everything else is calling for troubles.
That being said, concessions are sometimes made, e.g. in cases of hierarchies where virtual methods are required to be called in order to provide type specific initialization. Oftentimes, this can be avoided by usage of template classes/methods (i.e. static polymorphism)
If there are class members which don't affect the class invariant, they can be set later on via setters or other methods.
the builder pattern will help here also try to coalesce the parameters to have them make sense during the setting up of the builder
As a rule of thumb, having lots of constructor parameters is a sign of a class that does too much, so try splitting it into smaller classes first.
Then try grouping some of the parameters into smaller classes or structs having their own, simpler, constructor each.
If you have sensible default values, you can use a constructor that provides parameters only for values that absolutely MUST be given when constructing a new object, and then add setters, or use static functions that copy a "starter" object, changing part of it in the process. That way, you always have consistent objects (invariants OK), and shorter constructor or function calls.
I agree with ratchet freak's suggestion of the builder pattern except that there is a trade-off in that the typical builder pattern offers no compile-time checks to insure all arguments have been included, and you can end up with an incompletely/incorrectly built object.
This was a problem enough for me that I make a compile-time checking version that might do the job for you if you can forgive the extra machinery. (There are certainly optimizations to be had as well)
#include <boost/shared_ptr.hpp>
class Thing
{
public:
Thing( int arg0, int arg1 )
{
std::cout << "Building Thing with \n";
std::cout << " arg0: " << arg0 << "\n";
std::cout << " arg1: " << arg1 << "\n";
}
template <typename CompleteArgsT>
static
Thing BuildThing( CompleteArgsT completeArgs )
{
return Thing( completeArgs.getArg0(),
completeArgs.getArg1() );
}
public:
class TheArgs
{
public:
int arg0;
int arg1;
};
class EmptyArgs
{
public:
EmptyArgs() : theArgs( new TheArgs ) {};
boost::shared_ptr<TheArgs> theArgs;
};
template <typename PartialArgsClassT>
class ArgsData : public PartialArgsClassT
{
public:
typedef ArgsData<PartialArgsClassT> OwnType;
ArgsData() {}
ArgsData( const PartialArgsClassT & parent ) : PartialArgsClassT( parent ) {}
class HasArg0 : public OwnType
{
public:
HasArg0( const OwnType & parent ) : OwnType( parent ) {}
int getArg0() { return EmptyArgs::theArgs->arg0; }
};
class HasArg1 : public OwnType
{
public:
HasArg1( const OwnType & parent ) : OwnType( parent ) {}
int getArg1() { return EmptyArgs::theArgs->arg1; }
};
ArgsData<HasArg0> arg0( int arg0 )
{
ArgsData<HasArg0> data( *this );
data.theArgs->arg0 = arg0;
return data;
}
ArgsData<HasArg1> arg1( int arg1 )
{
ArgsData<HasArg1> data( *this );
data.theArgs->arg1 = arg1;
return data;
}
};
typedef ArgsData<EmptyArgs> Args;
};
int main()
{
Thing thing = Thing::BuildThing( Thing::Args().arg0( 2 ).arg1( 5 ) );
return 0;
}
It rather depends on what you're doing. Usually it's best to set things in the constructor as these help shape how the object is used later in its lifecycle. There can also be implications of changing a value once the object has been created (e.g. a calculation factor, or file name) which might mean you have to provide functionality to reset the object - very messy.
There are sometimes arguments for providing an initialization function which is called after the constructor (when calling a pure virtual would make it difficult to initialize direct from the constructor) but you then have to keep a record of object state which adds more complexity.
If the object is a straight stateless data container then accessors and mutators might be OK but they add a lot of maintenance overhead and are rarely all used anyway.
I'd tend to stick with setting your values in the constructor and then adding accessors as and when to allow you read only access to arguments that you might need.
That depends on your architecture and tools:
If you plan to develop/prototype a large OO-hierarchy, i'd be reluctant with passing lots of information via constructors if you don't have a good IDE/editor. In this case you might end up with a lot of work each refactoring step, which might result in errors, not catched by the compiler.
If you plan to use a well integrated set of objects (e.g. through strong use of design patterns) which do not span one large hierarchy, but rather have strong iteraction, passing more data via constructors is a good thing, since changing one objects constructor does not break all the child constructors.
If the setting is required and cannot be given a default value, make it required in the constructor. That way you know it will actually be set.
If the setting is not required and can be given a default value, make a setter for it. This makes the constructor a lot simpler.
e.g. If you have a class that sends an email, the "To" field might be required in the constructor, but everything else can be set in a setter method.
My experience points me to having arguments in the constructor rather than getters and setters. If you have a lot of parameters, it suggests optional ones can be defaulted while the required/mandatory ones are the constructor parameters.
I have a function that processes a given vector, but may also create such a vector itself if it is not given.
I see two design choices for such a case, where a function parameter is optional:
Make it a pointer and make it NULL by default:
void foo(int i, std::vector<int>* optional = NULL) {
if(optional == NULL){
optional = new std::vector<int>();
// fill vector with data
}
// process vector
}
Or have two functions with an overloaded name, one of which leaves out the argument:
void foo(int i) {
std::vector<int> vec;
// fill vec with data
foo(i, vec);
}
void foo(int i, const std::vector<int>& optional) {
// process vector
}
Are there reasons to prefer one solution over the other?
I slightly prefer the second one because I can make the vector a const reference, since it is, when provided, only read, not written. Also, the interface looks cleaner (isn't NULL just a hack?). And the performance difference resulting from the indirect function call is probably optimized away.
Yet, I often see the first solution in code. Are there compelling reasons to prefer it, apart from programmer laziness?
I would not use either approach.
In this context, the purpose of foo() seems to be to process a vector. That is, foo()'s job is to process the vector.
But in the second version of foo(), it is implicitly given a second job: to create the vector. The semantics between foo() version 1 and foo() version 2 are not the same.
Instead of doing this, I would consider having just one foo() function to process a vector, and another function which creates the vector, if you need such a thing.
For example:
void foo(int i, const std::vector<int>& optional) {
// process vector
}
std::vector<int>* makeVector() {
return new std::vector<int>;
}
Obviously these functions are trivial, and if all makeVector() needs to do to get it's job done is literally just call new, then there may be no point in having the makeVector() function. But I'm sure that in your actual situation these functions do much more than what is being shown here, and my code above illustrates a fundamental approach to semantic design: give one function one job to do.
The design I have above for the foo() function also illustrates another fundamental approach that I personally use in my code when it comes to designing interfaces -- which includes function signatures, classes, etc. That is this: I believe that a good interface is 1) easy and intuitive to use correctly, and 2) difficult or impossible to use incorrectly . In the case of the foo() function we are implictly saying that, with my design, the vector is required to already exist and be 'ready'. By designing foo() to take a reference instead of a pointer, it is both intuitive that the caller must already have a vector, and they are going to have a hard time passing in something that isn't a ready-to-go vector.
I would definitely favour the 2nd approach of overloaded methods.
The first approach (optional parameters) blurs the definition of the method as it no longer has a single well-defined purpose. This in turn increases the complexity of the code, making it more difficult for someone not familiar with it to understand it.
With the second approach (overloaded methods), each method has a clear purpose. Each method is well-structured and cohesive. Some additional notes:
If there's code which needs to be duplicated into both methods, this can be extracted out into a separate method and each overloaded method could call this external method.
I would go a step further and name each method differently to indicate the differences between the methods. This will make the code more self-documenting.
While I do understand the complaints of many people regarding default parameters and overloads, there seems to be a lack of understanding to the benefits that these features provide.
Default Parameter Values:
First I want to point out that upon initial design of a project, there should be little to no use for defaults if well designed. However, where defaults' greatest assets comes into play is with existing projects and well established APIs. I work on projects that consist of millions of existing lines of code and do not have the luxury to re-code them all. So when you wish to add a new feature which requires an extra parameter; a default is needed for the new parameter. Otherwise you will break everyone that uses your project. Which would be fine with me personally, but I doubt your company or users of your product/API would appreciate having to re-code their projects on every update. Simply, Defaults are great for backwards compatibility! This is usually the reason you will see defaults in big APIs or existing projects.
Function Overrides:
The benefit of function overrides is that they allow for the sharing of a functionality concept, but with with different options/parameters. However, many times I see function overrides lazily used to provide starkly different functionality, with just slightly different parameters. In this case they should each have separately named functions, pertaining to their specific functionality (As with the OP's example).
These, features of c/c++ are good and work well when used properly. Which can be said of most any programming feature. It is when they are abused/misused that they cause problems.
Disclaimer:
I know that this question is a few years old, but since these answers came up in my search results today (2012), I felt this needed further addressing for future readers.
I agree, I would use two functions. Basically, you have two different use cases, so it makes sense to have two different implementations.
I find that the more C++ code I write, the fewer parameter defaults I have - I wouldn't really shed any tears if the feature was deprecated, though I would have to re-write a shed load of old code!
A references can't be NULL in C++, a really good solution would be to use Nullable template.
This would let you do things is ref.isNull()
Here you can use this:
template<class T>
class Nullable {
public:
Nullable() {
m_set = false;
}
explicit
Nullable(T value) {
m_value = value;
m_set = true;
}
Nullable(const Nullable &src) {
m_set = src.m_set;
if(m_set)
m_value = src.m_value;
}
Nullable & operator =(const Nullable &RHS) {
m_set = RHS.m_set;
if(m_set)
m_value = RHS.m_value;
return *this;
}
bool operator ==(const Nullable &RHS) const {
if(!m_set && !RHS.m_set)
return true;
if(m_set != RHS.m_set)
return false;
return m_value == RHS.m_value;
}
bool operator !=(const Nullable &RHS) const {
return !operator==(RHS);
}
bool GetSet() const {
return m_set;
}
const T &GetValue() const {
return m_value;
}
T GetValueDefault(const T &defaultValue) const {
if(m_set)
return m_value;
return defaultValue;
}
void SetValue(const T &value) {
m_value = value;
m_set = true;
}
void Clear()
{
m_set = false;
}
private:
T m_value;
bool m_set;
};
Now you can have
void foo(int i, Nullable<AnyClass> &optional = Nullable<AnyClass>()) {
//you can do
if(optional.isNull()) {
}
}
I usually avoid the first case. Note that those two functions are different in what they do. One of them fills a vector with some data. The other doesn't (just accept the data from the caller). I tend to name differently functions that actually do different things. In fact, even as you write them, they are two functions:
foo_default (or just foo)
foo_with_values
At least I find this distinction cleaner in the long therm, and for the occasional library/functions user.
I, too, prefer the second one. While there are not much difference between the two, you are basically using the functionality of the primary method in the foo(int i) overload and the primary overload would work perfectly without caring about existence of lack of the other one, so there is more separation of concerns in the overload version.
In C++ you should avoid allowing valid NULL parameters whenever possible. The reason is that it substantially reduces callsite documentation. I know this sounds extreme but I work with APIs that take upwards of 10-20 parameters, half of which can validly be NULL. The resulting code is almost unreadable
SomeFunction(NULL, pName, NULL, pDestination);
If you were to switch it to force const references the code is simply forced to be more readable.
SomeFunction(
Location::Hidden(),
pName,
SomeOtherValue::Empty(),
pDestination);
I'm squarely in the "overload" camp. Others have added specifics about your actual code example but I wanted to add what I feel are the benefits of using overloads versus defaults for the general case.
Any parameter can be "defaulted"
No gotcha if an overriding function uses a different value for its default.
It's not necessary to add "hacky" constructors to existing types in order to allow them to have default.
Output parameters can be defaulted without needing to use pointers or hacky global objects.
To put some code examples on each:
Any parameter can be defaulted:
class A {}; class B {}; class C {};
void foo (A const &, B const &, C const &);
inline void foo (A const & a, C const & c)
{
foo (a, B (), c); // 'B' defaulted
}
No danger of overriding functions having different values for the default:
class A {
public:
virtual void foo (int i = 0);
};
class B : public A {
public:
virtual void foo (int i = 100);
};
void bar (A & a)
{
a.foo (); // Always uses '0', no matter of dynamic type of 'a'
}
It's not necessary to add "hacky" constructors to existing types in order to allow them to be defaulted:
struct POD {
int i;
int j;
};
void foo (POD p); // Adding default (other than {0, 0})
// would require constructor to be added
inline void foo ()
{
POD p = { 1, 2 };
foo (p);
}
Output parameters can be defaulted without needing to use pointers or hacky global objects:
void foo (int i, int & j); // Default requires global "dummy"
// or 'j' should be pointer.
inline void foo (int i)
{
int j;
foo (i, j);
}
The only exception to the rule re overloading versus defaults is for constructors where it's currently not possible for a constructor to forward to another. (I believe C++ 0x will solve that though).
I would favour a third option:
Separate into two functions, but do not overload.
Overloads, by nature, are less usable. They require the user to become aware of two options and figure out what the difference between them is, and if they're so inclined, to also check the documentation or the code to ensure which is which.
I would have one function that takes the parameter,
and one that is called "createVectorAndFoo" or something like that (obviously naming becomes easier with real problems).
While this violates the "two responsibilities for function" rule (and gives it a long name), I believe this is preferable when your function really does do two things (create vector and foo it).
Generally I agree with others' suggestion to use a two-function approach. However, if the vector created when the 1-parameter form is used is always the same, you could simplify things by instead making it static and using a default const& parameter instead:
// Either at global scope, or (better) inside a class
static vector<int> default_vector = populate_default_vector();
void foo(int i, std::vector<int> const& optional = default_vector) {
...
}
The first way is poorer because you cannot tell if you accidentally passed in NULL or if it was done on purpose... if it was an accident then you have likely caused a bug.
With the second one you can test (assert, whatever) for NULL and handle it appropriately.