Constructor delegation vs default arguments

Viewed 258

I am wondering which of the following classes implements the preferred method:

class foo
{
public:
    foo(int a, int b, int c);
    foo(int a, int b) : foo(a, b, 0){};
    ~foo();
    //...
};

class bar
{
public:
    bar(int a, int b, int c = 0);
    ~bar();
    //...
};

From my point of view, they basically do the same. I would personally prefer the bottom one, because less code (to maintain). But is my preference the best practice?

2 Answers

The first snippet generates more typing and potentially more maintenance (for example the type of a might change and that could even change in a way that breaks overload resolution).

So prefer the second way. (Although note that some languages, e.g. Java disallow default arguments).

There is a principle in programming: Don't Repeat Yourself.

Reference: https://en.wikipedia.org/wiki/Don%27t_repeat_yourself

(On the other side of the argument, note that default arguments are not part of the function signature: std::function does not recognise them for example. So occasionally you have to resort to function overloading).

The default argument way has been the historical C++ way. The delegating way was the standard way in other languages such as Java. It was introduced in C++ 11 to allow a smoother transition for Java programmers and because it can be slightly more versatile than a simple default value. Here is an example where a default value would not be enough:

class foo {
private:
    foo() {
        // various initialization tasks
        ...
    }

public:
    foo(int val): foo() {
        // processing using val
        ...
    }
    foo(const std::string &file_path): foo() {
        // use a config file
        ...
    }
}

Here you have 2 different (public) constructors that delegate their common tasks to a private one.

You have 3 ways for combining different constructors:

  1. default values in one ctor
  2. ctor delegation
  3. various constructors use common initialization methods

The rule is use the method that allow the less code duplication for you use case because of the Don't Repeat Yourself principle.

For you example, the default value in a single constructor should be prefered.

Related