简体   繁体   中英

Calling superclass constructor from constructor's body

I want to create a class constructor which will call it's superclass constructor only on certain condition. My current implementation of this is shown below.

class MyClass : public OtherClass
{
public:
    template<typename... Args>
    MyClass(bool condition, Args&&... args)
    {
        if(condition)
        {
            *(OtherClass*)this = OtherClass(args...);
        }
        else
        {
            //  Unrelated stuff
        }
    }
};

I can't use MyClass(...) : OtherClass(...) {} syntax here because superclass's constructor should not be called every time.

Is there any way to call superclass constructor directly instead of calling move constructor (as shown in my example).

You could create 2 different constructors for both the base- and the derived class.
The constructor of the derived class calls the appropriate constructor of the base class.
A static method within the derived class creates an instance based on the passed arguments.
Something like this:

class OtherClass
{
  public:

    OtherClass()
    {
      ...
    }

    OtherClass(Args&... args)
    {
      ...
    }

} // class OtherClass

class MyClass: public OtherClass
{
  private:

    MyClass(): OtherClass()
    {
      ...
    }

    MyClass(Args&... args): OtherClass(args)
    {
      ...
    }

  public:

    static MyClass* createInstance(bool      condition,
                                   Args&&... args)
    {
      if (condition)
        return (new MyClass());
      else
        return (new MyClass(args));
    }

} // class MyClass

A solution is to not do this in the constructor, but in a helper function. For example:

class BaseClass {
    BaseClass() {}
    BaseClass(int x) {setX(x);}
    void setX(int x) {
        //thing
    }
}

class Derived : BaseClass {
    Derived(int x) {
        if (x>10) setX(x);
    }
}

You could overload the constructor in the following way to implement tag dispatching :

struct PassArgs {};
struct DoNotPassArgs {};

class MyClass: public OtherClass {
public:
    template<typename... Args>
    MyClass(PassArgs, Args&&... args) : OtherClass(args...) {}

    template<typename... Args>
    MyClass(DoNotPassArgs, Args&&...) : OtherClass() {}
};

Above answer from Robert Kock is not perfectly correct. He is calling Base class (supper class) constructor from initialization list of derived class constructor but without a condition. But as per your question can we call a base class constructor based on a CONDITION from the BODY of derived class constructor? . The answer is NO we can not. As per object oriented principle A Base class constructor must call and initialized first. In the above answer from Robert Kock, base class constructor is called from the initialization list of drive class constructor before control enter inside the body and without any condition. In the initialization list you can not even put any condition. So it is not possible to call a based class constructor to call from the body of a derive class constructor. That is the reason for this kind of requirement we introduce one more method called init() in a class. Now the below example can full fill your requirement. Here in this example you have to add one default constructor in your base class, so that this default constructor call first but in that default constructor you are not going to do anything.

Now see the below example:-

#include<iostream>

class B
{
  private:
  int x;
  int y;

  public:
  B(){std::cout<<"I am B's default constructor"<<std::endl;}//Default constructor not doing anything
  void init(int x)
  {
    std::cout<<"Based init with param x"<<std::endl;
    this->x = x; //this method initializing only one member
    y = 0;// just initialized with default value 0
  }
  void init(int x,int y)
  {
    std::cout<<"Based init with param x and y"<<std::endl;
    this->x = x; // here we initializing all the members
    this->y = y;
  }
  void print()
  {
    std::cout<<"x ="<<x<<std::endl;
    std::cout<<"y ="<<y<<std::endl;
  }
};

class D : public B
{
  public:
  D(int i)
  {
    std::cout<<"I am D's constructor"<<std::endl;
    if( i == 1 )
       B::init(3);
    else
       B::init(4, 5);
  }
};

int main()
{
   std::cout<<"First Example"<<std::endl;
   D *d = new D(1);
   d->print();
   std::cout<<"Now second Example"<<std::endl;
   D *d1 = new D(2);
   d1->print();
   return 0;
} 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM