2

I'm looking for a way to define a "base" constructor, that will initialize values using defaults, and then extend that base into a number of specialized constructors.

The pseudocode of what I want might look like:

class Foo{
private:
    int val;
    /* ... */

public:
    // Base constructor
    Foo(){ /*...*/ }           // This provides basic initialization of members

    // Named constructors
    static Foo fromString(string s){
        Foo f;                 // Call base constructor
        f.val = s.length();    // Customize base object
        return f;              // Return customized object
    }
    static Foo fromInt(int v){
        Foo f;
        f.val = v;
        return f;
    }
}

At first, I thought about extending the lifetime of the temporary f, but the const declaration prevents me from editing its members. So it seems this is out.

Then I tried the "named constructor" approach (which is shown above). However, I had to modify the example to create the object first, then modify it, then return it. This seems to work, but I'm reasonably confident that it is just a coincidence since f is a temporary and goes out of scope at the end of the function.

I've also considered using something like auto_ptrs, but then I'm working with both Foo objects as well as auto_ptrs to Foo, and this makes the rest of the code "care" whether objects are created via the base constructor (in which case it would be an object) or via one of the extended constructors (in which case it would be a pointer).

If it helps, in Python, I would use something like this:

class Foo(object):
    def __init__(self):
        /* Basic initialization */

    @classmethod
    def fromString(cls, s):
        f = Foo() #†
        f.val = len(s)
        return f

Lastly, there are two reasons I want to do it this way:

  1. Code reuse, I would like to move the common initialization out of each of the constructors and into one. I realize I can do this via an init()-type private method called by each constructor, but I just wanted to mention this.
  2. Clarity and resolve ambiguity. Much like the motivation for the named constructor example, parameter types by themselves aren't enough to determine which ctor should be used. Additionally, the fromSomething syntax provides excellent clarity.

Forgive me if there is a simple solution, my work has shifted from c++ to Java/Python for the past few years so I'm a bit rusty.

Community
  • 1
  • 1
jedwards
  • 29,432
  • 3
  • 65
  • 92

3 Answers3

6

This is perfectly valid:

static Foo fromInt(int v){
    Foo f;
    f.val = v;
    return f;
}

This invokes Foo's copy constructor when you return f(probably the compiler applies return value optimization, so no copies are made). f goes out of scope, but the return value is just a copy of it, so this is totally valid, it's not just "a coincidence" that it's working.

So if your worries about using the named constructor approach is just that you don't really know if it works, go ahead with it, it works perfectly.

mfontanini
  • 21,410
  • 4
  • 65
  • 73
  • Actually, that was exactly my worry. I know that there are a lot of places that c++ works "by accident" and I just wanted to make sure this wasn't one of those cases. – jedwards Jul 06 '12 at 16:12
  • I agree, using named constructors make it more clear from the API point of view. This is also known as a static factory. – hopia Jul 06 '12 at 16:18
  • @jedwards yes, you don't have to worry at all about it. There will probably be no copies, so this should be as efficient as a constructor taking an int. – mfontanini Jul 06 '12 at 16:21
2

In C++11, you can call other constructors from constructors:

struct X{
  X() : ... { ... }
  X(int i) : X() { ... }
  X(std::string s) : X() { ... }
};

For C++03, the named constructor approach is likely the best and perfectly reasonable, IMHO.

Xeo
  • 129,499
  • 52
  • 291
  • 397
  • This might be a good solution - depends on what the default constructor is doing. The parameter in the others may prevent the default from doing a lot of work (e.g. creating network connections etc). – Ed Heal Jul 06 '12 at 16:15
0

Why not:

class Foo{
private:
    int val;
    void Init(int v = <some default value>/*What ever here *));
    /* ... */


public:
    // Base constructor
    Foo(){ Init(); }           // This provides basic initialization of 
    Foo(string &s) { Init(s.length); };
    Foo(int v) { Init(v); };
};

Seems simpler.

Ed Heal
  • 59,252
  • 17
  • 87
  • 127
  • 2
    Wasted default initialization of the members. – Xeo Jul 06 '12 at 16:06
  • Basically, the constructors actually look like `Foo() : val(){ Init(); }`. – Xeo Jul 06 '12 at 16:13
  • @Xeo: You are right in that there is potentially an extra step of work, but it depends on the members stored. Also note that the example in the answer and your *look-alike* have different semantics. Not mentioning a POD object in the initialization list leaves it uninitialized, while your code *value-initializes* it. That is, you are incurring the cost that the answer is not doing in this particular case. --The story would be different if the members had default constructors that actually did some work. – David Rodríguez - dribeas Jul 06 '12 at 16:21