Вызов конструктора базового класса после некоторых других инструкций в С++

Насколько я знаю, невозможно вызвать конструктор базового класса. Единственное, что я знаю, это:

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

но это вызывает конструктор в начале. Есть ли способ вызвать его где-то еще в конструкторе? Что-то вроде этого:

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

В соответствии с этим Каковы правила для вызова конструктора суперкласса? вопрос я понимаю, что нет способа, но я читаю здесь, и я догадался, что это возможно, но если я попробую, я получу:

error: invalid use of 'class Base'.

Я что-то делаю неправильно? Возможно ли это сделать каким-то образом или есть ли другое возможное решение этой проблемы?

Спасибо!

EDIT: Я понимаю, что я забыл ключевой момент: базовый класс является частью структуры, и поэтому было бы неплохо не изменять его, если это возможно.

Ответ 1

Если конструктор базового класса принимает хотя бы один аргумент, вы можете использовать вспомогательную функцию следующим образом:

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

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

Если вы хотите инициализировать базовый класс по умолчанию, вы можете использовать copy-ctor для копирования инициализированного базового класса по умолчанию:

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

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

Или, если Base не должен быть первым базовым классом, вы можете получить MyClass из вспомогательного класса:

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

Все вышеизложенное требует, чтобы "материал", который вы делаете, не зависел от объекта, который должен быть инициализирован (то есть функции не могут безопасно быть функциями-членами, и вы не можете безопасно передать this в качестве аргумента для них либо).

Это означает, что вы можете сделать некоторые записи или подобные, но затем вы также можете сделать это после инициализации базового класса.

( РЕДАКТИРОВАТЬ, за исключением решения DoStuffHelperClass, вы можете, конечно, иметь членов в DoStuffHelperClass, получить к ним доступ, а что нет)


Хотя я должен сказать, что я не могу вспомнить, когда-либо использовал/нуждался/хотел что-то подобное. Весьма вероятно, что есть другое (предпочтительное) решение для того, что вы пытаетесь сделать.

Ответ 2

Базовый класс всегда полностью построен до начала создания собственного класса. Если вам нужно внести изменения в состояние базового класса, вы должны сделать это явно после того, как он был создан.

Пример:

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

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

    // ... 
}

Ответ 3

Используйте идентификатор базы-от-члена, чтобы запустить свой код перед ctor "реального" базового класса (который является базой):

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.
};

Это работает, даже если у вас нет фактических членов, которые вы хотите в DerivedDetail. Если вы дадите более подробную информацию о том, что вы должны сделать до Base ctor, я могу привести лучший пример.

Ответ 4

Помимо уже написанных решений, вы также можете использовать статическую конструкторскую функцию и сделать конструктор 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;
};

Теперь вам нужно будет создавать экземпляры MyClass либо как:

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

или

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

Ответ 5

нет, поскольку он не будет безопасным по типу. У вас есть: класс A и переменная A.var. Теперь рассмотрим B наследует от A и использует var до того, как A был инициализирован. вы получите ошибку времени выполнения! язык хочет предотвратить это, поэтому сначала должен быть инициализирован конструктор суперкласса.

Ответ 6

Нет, вы не можете так поступать, как описано в предыдущих ответах.

Ваш единственный шанс - состав, IOW, что MyClass использует класс Base как поле участника:

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

private:
   Base* _base;
};

чтобы позже вы могли инициализировать _base, когда у вас есть необходимая информация. В любом случае, я не знаю, может ли это примениться к вашему сценарию.

Ответ 7

Нет. Это невозможно, потому что порядок вызовов конструктора строго определен стандартом. Базовый класс ctor должен выполняться до того, как можно выполнить класс ctor.