Вызов конструктора базового класса после некоторых других инструкций в С++
Насколько я знаю, невозможно вызвать конструктор базового класса. Единственное, что я знаю, это:
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.