marolafm
marolafm

Reputation: 345

Conditional call to base constructor

Currently, I have a based class with two different constructors:

class Base {
public:
   Base(std::string filname){...}
   Base(int a, int b) {...}
};

and a derived class of Base class. What I would like to do is to choose which constructor call inside the constructor of the derived class, but not in the initializer list. Something like this:

class Derived : public Base {
public:
    Derived() {
        if( /* exists("myFile") */ )
            this->Base("myFile");
        else
            this->Base(1,2);
    }
}

Is it possible to do that?, or because the base class is initialize before the derived class, the only way to call to the base constructor is in the initializer list?

Thanks

Upvotes: 7

Views: 2539

Answers (3)

Martin Hierholzer
Martin Hierholzer

Reputation: 930

Based on @DanielH comment in his answer I have developed an alternative solution which also works with abstract base classes in C++11:

#include <iostream>


struct Base {

    Base(int x) {
      std::cout << "Base x = " << x << std::endl;
    }
    
    Base() {
      std::cout << "Base default" << std::endl;
    }

    virtual void foo() = 0;

};


struct Derived : Base {

    struct TagA {};
    struct TagB {};

    Derived(bool condition)
    : Derived(condition ? Derived{TagA()} : Derived{TagB()})
    {}
    
    void foo() override {}
    
  private:
  
    Derived(TagA dummy)
    : Base(42)
    {
      std::cout << "Derived A dummy" << std::endl;
    }
    Derived(TagB dummy)
    {
      std::cout << "Derived B dummy" << std::endl;
    }



};


int main() {

    std::cout << "Construct Derived with false" << std::endl; 
    Derived x(false);

    std::cout << "Construct Derived with true" << std::endl; 
    Derived y(true);
  

}

Upvotes: 1

Maxim Egorushkin
Maxim Egorushkin

Reputation: 136246

You can simulate that by introducing a factory function:

class Base {
public:
    Base(std::string filname);
    Base(int a, int b);
};

class Derived : public Base {
    Derived(std::string filname) : Base(filname) {}
    Derived(int a, int b) : Base(a, b) {}
public:
    static Derived create() {
        if( /* exists("myFile") */ )
            return Derived("myFile");
        else
            return Derived(1,2);
    }
};

int main(){
    auto d = Derived::create();
}

Alternatively, if derivation from Base is not required, an instance of Base can be held as a member (std::unique_ptr or std::aligned_storage) that you can initialise however you please.

Upvotes: 1

Daniel H
Daniel H

Reputation: 7433

The choice of which base constructor is called happens before the body of the function and there's no way to change it at run time like that. However, you might be able to get close. If the base class also has a move constructor, or you could you add one, you could use that:

class Derived : public Base {
public:
    Derived()
        : Base{ exists("myFile") ? Base{"myFile"} : Base{1, 2} } {
    }
}

This will call exists("myFile"); if that returns true, it will construct a temporary Base using the first constructor, and if it returns false it will construct a temporary Base using the second constructor. Either way, it will then construct the actual base subobject using this temporary.

Upvotes: 8

Related Questions