12

I'm trying to create an object in C++ that requires multiple object constructors. Say Foo() and Foo(int) where Foo(int) then calls Foo(). The simplified code is written below:

#include <iostream>
class Foo{

private:
        int iX; 

public:
        void printX(string sLabel){
            cout << sLabel << " : " << " Foo::iX = " << Foo::iX << endl;
        };  
        void setX(int iX){
            Foo::iX = iX; 
            Foo::printX("setX(void) Method");
        };  
        Foo(){
            Foo::iX = 1;
            Foo::printX("Foo(void) Constructor");
        };
        Foo(int iX){
            Foo::setX(iX);
            Foo::printX("Foo(int) Constructor");
            Foo::Foo();
            Foo::printX("Foo(int) Constructor");

        };  
};

int main( int argc, char** argv ){

    Foo bar(2);

    return 0;
}

The output of which is

setX(void) Method :  Foo::iX = 2
Foo(int) Constructor :  Foo::iX = 2
Foo(void) Constructor :  Foo::iX = 1
Foo(int) Constructor :  Foo::iX = 2

As the results indicate setX method works as expected. Foo::iX is equal to 2 inside and outside of scope of that function.

However when calling the Foo(void) constructor from within the Foo(int) constructor, Foo::iX stays equal to 1 only within that constructor. As soon as it exits out that method, it reverts back to 2.

So my question is 2-fold:

  1. Why does C++ behave this (a constructor cannot be called from within another constructor without values that were assigned)?
  2. How can you create multiple constructor signatures, but without redundant duplicate code doing the same thing?
songyuanyao
  • 169,198
  • 16
  • 310
  • 405
WoodMath
  • 521
  • 2
  • 8
  • 14
  • Read about _delegating constructors_. Also read up on _member initialization_. For example [here](http://en.cppreference.com/w/cpp/language/initializer_list). – Torbjörn Aug 29 '16 at 05:31

3 Answers3

16

Foo::Foo(); in Foo::Foo(int) is not invoking the default constructor on the current object as you expected. It just constructs a temporary Foo, which has nothing to with the current object.

You can use delegating constructor (since C++11) like this:

Foo(int iX) : Foo() {
    // ...
}; 

Note that Foo::Foo() will be invoked in advance of the body of Foo::Foo(int) here.

An alternative to avoid duplicated code is to use setX() as a common initialization method. (Or make a new one if not appropriate.)

Foo() {
    setX(1);
    // ...
};
Foo(int iX) {
    setX(iX);
    // ...
}; 
songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • @songyuanyaho : How do you define temporary? In a general sense or a more technical sense? Please explain. Thx. – WoodMath Aug 29 '16 at 16:19
  • @WoodMath In more technical sense. The default constructor is invoked explicitly to create a temporary object, which is discarded immediately. – songyuanyao Aug 30 '16 at 05:28
7

If you are able to use a C++11 compiler, you can use delegating constructors.

// Use Foo(int) to initialize the object when default constructor is used.
Foo() : Foo(1) {}
R Sahu
  • 204,454
  • 14
  • 159
  • 270
3

A constructor CAN be called from within another constructor. You just forget to assign the return value.

*this = Foo::Foo();

For question 2, you need delegating constructors.

Foo(int iX) : Foo() {
    ...
}
Wiki Wang
  • 668
  • 6
  • 23
  • `*this = Foo:Foo()` will only work if assignment can cope with a partially constructed object. (All the members and bases will be properly constructed, but the constructor has not completed, so the lifetime of the object itself has not begun.) – Martin Bonner supports Monica Aug 29 '16 at 08:00