简体   繁体   中英

Calling the constructor of the base class after some other instructions in C++

As far as I know it is not possible to call the constructor of the base class. The only way I know is this:

MyClass::MyClass(/* args */) : Base(/* args */)
{
   // ...
}

but this would invoke the constructor at the beginning. Is there any way to call it somewhere else in the constructor? Something like this:

MyClass::MyClass(/* args */)
{
   // ... instructions
   Base::Base(/* args */);
   // ... other_instructions
}

According to this What are the rules for calling the superclass constructor? question I understand there is no way but I read here and I guessed it was possible, but if I try I get:

error: invalid use of 'class Base'.

Am I doing something wrong? Is it possible to do this some way or is there any other possible solution to this need?

Thanks!

EDIT: I understand I forgot a key point: the base class is part of a framework, and therefore it would be good not to have to modify it, if possible.

If the base class constructor takes at least one argument, you could use a helper function like this:

int DoStuffBeforeCtorAndForwardInt(int arg, Foo foo)
{
    DoStuff(arg, foo);
    return arg;
}

MyClass::MyClass(int arg, Foo foo)
    : Base(DoStuffBeforeCtorAndForwardInt(arg, foo))
{
   // ...
}

If you want to default-initialize the base class, you could use the copy-ctor to copy a default initialized base class instance:

Base DoStuffBeforeCtorAndReturnDefaultBase(int arg, Foo foo)
{
    DoStuff(arg, foo);
    return Base();
}

MyClass::MyClass(int arg, Foo foo)
    : Base(DoStuffBeforeCtorAndReturnDefaultBase(arg, foo))
{
   // ...
}

Or, if Base doesn't have to be the first base class, you could derive MyClass from a helper class:

MyClass::MyClass(/* ... */)
    : DoStuffHelperClass(/* ... */),
    Base(/* ... */)
{
   // ...
}

All of the above require that the "stuff" you do does not depend on the object that's about to be initialized (ie the functions can't safely be member functions and you cannot safely pass this as an argument to them either).

That means you can do some logging or similar, but then again you could also do that after the base class has been initialized.

( EDIT except with the DoStuffHelperClass solution, you can of course have members in DoStuffHelperClass, access them and what not)


Although I have to say that I can't recall ever using/needing/wanting something like that. It's quite probable that there is another (preferable) solution for what you're trying to do.

Use the base-from-member idiom to run your code before the ctor of the "real" base class (which is Base):

struct Base {
  Base(string, int);
};

struct DerivedDetail {
  DerivedDetail() {
    value = compute_some_value();
    value += more();
    value += etc();
    other = even_more_code(value);
  }
  string value;
  int other;
};

struct Derived : private DerivedDetail, Base {
  Derived() : Base(value, other) {}
  // In particular, note you can still use this->value and just
  // ignore that it is from a base, yet this->value is still private
  // within Derived.
};

This works even if you don't have actual members you want in DerivedDetail. If you give more specifics on what you must do before the Base's ctor, then I can give a better example.

The base class is always fully constructed before construction of your own class begins. If you need to make a change to the state of the base class, you have to do that explicitly after it has been constructed.

Example:

MyClass::MyClass()
{
    // Implicit call to Base::Base()

    int result = computeSomething();
    Base::setResult(result);

    // ... 
}

Besides the already written solutions, you can also use a static constructor function and make the contructor of MyClass private.

class QtBase{
  // ...
};

class MyClass : public QtBase{
public:
  // copy ctor public
  MyClass(MyClass const& other);

  static MyClass Create(/*args*/){
    // do what needs to be done
    int idata;
    float fdata;
    // work with idata and fdata as if they were members of MyClass
    return MyClass(idata,fdata); // finally make them members
  }

  static MyClass* New(/*args*/){
    int idata;
    float fdata;
    // work with idata and fdata as if they were members of MyClass
    return new MyClass(idata,fdata); // finally make them members
  }

private:
  // ctor private
  MyClass(int a_idata, float a_fdata)
    : idata(a_idata)
    , fdata(a_fdata)
  {}

  int idata;
  float fdata;
};

Now you would have to create instances of MyClass either as:

MyClass obj = MyClass::Create(/*args*/);

or

MyClass* ptr = MyClass::New(/*args*/);

no, because it will not be type safe.
consider you have: a class A and a variable A.var .
now consider B inherits from A , and uses var before A was initialized. you will get a run time error, the language wants to prevent this. thus superclass constructor must be initialized first.

No, you can't do it that way, as other have described in their previous answers.

Your only chance is composition, IOW that MyClass uses Base class as a member field:

class MyClass {
public:
   /** the methods... */

private:
   Base* _base;
};

so you can initialize _base later, when you have the needed info. I don't know if this can apply to your scenario, anyway.

No. It is not possible, because the order of constructor calls is strictly defined by the standard. Base class ctor has to be executed before the derive class ctor can be executed.

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