Reusable constructors C++
Asked Answered
S

4

16

One of the corner stones of OOP is reusing code instead of repeat it over and over. Thus, your projects shorten and get more readable.

C++ gives you all the tools you need to reuse methods instead of repeating the code. Although when it comes to constructors I do not know how to reuse them.

I am not talking of heritage or how to send a message to the father. I am talking about reusing the constructor of the class itself.

The analogy in JAVA is something like this:

public Foo() {
    this(0,0,0);//Not needed in this case, just to clarify
}

public Foo(Foo f){
    this(f.getA(), f.getB(), f.getC());
}

public Foo(int a, int b, int c) {
    this.a = a;
    this.b = b;
    this.c = c;
}

My question is, is there any syntaxis in C++ that allows you to do so?

Selfmortification answered 5/10, 2011 at 21:3 Comment(0)
E
14

C++11 has added constructor delegation and constructor inheritance.

To inherit constructors, a using-declaration is required:

class Base { ... };

class Derived : public Base
{
    using Base::Base;
};

To delegate, use the ctor-initializer, but specify another constructor in the same class, instead of any subobjects (all base and member subobjects will be initialized by the constructor delegated to):

class Another : public Base
{
    int member;
    Another(int x)
        : Base(), member(x) // non-delegating constructor initializes sub-objects
    {}


    Another(void)
        : Another(5) // delegates -- other constructor takes care of Base and member
    {}
};

And perfect forwarding can also come in handy.

Elegist answered 5/10, 2011 at 21:5 Comment(0)
Q
11

Others already answered about C++11, but for C++03 there's a possible workaround: using a base class with needed constructor(s).

struct foo_base {
    foo_base(int a, int b, int c) : a(a), b(b), c(c) { }
    int a, b, c;
};

struct foo : foo_base {
    foo() : foo_base(0, 0, 0) { }
    foo(const foo& other) : foo_base(other.a, other.b, other.c) { }
    foo(int a, int b, int c) : foo_base(a, b, c) { }
};

Of course, you need to consider whether it's worth the boilerplate for your purposes.

Quarry answered 5/10, 2011 at 21:10 Comment(0)
S
2

The generally accepted soultion for current compilers is to do this:

class Bar{
pubilc:    
Foo() {
   init(0,0,0);
}

Foo(const Foo &f){
  init(f.getA(), f.getB(), f.getC());
}

Foo(int a, int b, int c) {
  init(a,b,c);
}

private:

void init(int a, int b, int c){
  this->a = a;
  this->b = b;
  this->c = c;
}
};

While this may seem like over kill in this example, that is only because of the simplicity of the example. In a real world application this would actually bring benefits in terms of reduction of repeated code.

Shadoof answered 5/10, 2011 at 21:11 Comment(6)
Sorry, java and c++ blur together for me sometimes. I edited my post so that it's entirely in valid c++ now assuming you have valid getA(), getB(), getC() functions.Shadoof
this.a is invalid, and copy constructor should take const reference as an argument.Quarry
Woops, sorry. Thanks for catching that Cat Plus Plus. Just go ahead and fix it next time.Shadoof
@Kurtis Nusbaum: Even if you had valid getA() would you use it? You have full accesses to all members of another object of the same type (it is assumed that you trust yourself to write good code).Nude
@LokiAstari Depends. I bet I could imagine some instances where getA() has some extra code in it that affects the state of the object and we'd want to get the value of a through that.Shadoof
Members should be assigned in the ctor-initializer list, for one thing it's the only way to set const members.Elegist
N
1

OK C++11 covers what you need.

But your simple case has an easy solution:

/* This one is covered by providing default parameters see below.
public Foo() {
    this(0,0,0);//Not needed in this case, just to clarify
}

 This is done automatically by the compiler.
 You do not need to write any code for this:
public Foo(Foo f){
    this(f.getA(), f.getB(), f.getC());
}
The compiler generated version actually looks like this:
public Foo(Foo const& f)
    : a(f.a)
    , b(f.b)
    , c(f.c)
{}



*/

// Now you can use all three methods and they work fine:
public Foo(int a = 0, int b = 0, int c = 0)
    : a(a)
    , b(b)
    , c(c)
{}

F   f1;        // default construct no parameters: uses the three parameter version
F   f2(f1);    // Copy constructed. Generated by the compiler.
F   f3(1,2,3); // Nomal constructor
Nude answered 5/10, 2011 at 23:14 Comment(1)
I am generally against using default values for parameters if not all the different permutations of how you can use it now make sense, i.e. now you have actually four ways to use Foo(int,int,int), which possibly does not make sense.Stewartstewed

© 2022 - 2024 — McMap. All rights reserved.