Вызов конструктора базового класса позже (не в списке инициализаторов) в С++
Я наследую класс, и я бы хотел назвать один из его конструкторов. Однако перед вызовом я должен обработать некоторые вещи (которые не требуют ничего из базового класса). Есть ли способ, который я могу просто назвать позже, вместо того, чтобы называть его в списке инициализаторов? Я считаю, что это можно сделать в Java и С#, но я не уверен в С++.
Данные, которые мне нужно передать конструктору, не могут быть переназначены позже, поэтому я не могу просто вызвать конструктор по умолчанию и инициализировать его позже.
Ответы
Ответ 1
Есть ли способ, которым я могу просто позвонить позже, вместо вызова его в списке инициализаторов?
Нет, вы не можете. Конструктор базового класса должен быть вызван в списке инициализаторов и должен быть вызван первым.
Фактически, если вы опустите его там, компилятор просто добавит вызов неявно.
Я считаю, что это можно сделать в Java и С#, но я не уверен в С++.
Ни С#, ни Java не разрешают это.
Однако вы можете вызвать метод как аргумент вызова конструктора базового класса. Затем он обрабатывается перед конструктором:
class Derived {
public:
Derived() : Base(some_function()) { }
private:
static int some_function() { return 42; }
};
Ответ 2
Как было сказано несколькими людьми, отвечающими, вы не можете отложить вызов конструктора базового класса, но Конрад дал хороший ответ, который может решить вашу проблему. Однако у этого есть свои недостатки (например, когда вам нужно инициализировать несколько функций со значениями, вычисления которых разделяют промежуточные результаты), поэтому просто для того, чтобы быть полным, вот еще один способ решения проблемы фиксированного порядка инициализации, используя ее.
Учитывая фиксированный порядок инициализации, если у вас есть контроль над производным классом (и как еще вы столкнулись с одним из своих ctors?), вы можете прокрасться в частную базу, чтобы она была инициализирована перед другой базой, которая затем может быть инициализирована с уже вычисленными значениями частной базы:
class my_dirty_little_secret {
// friend class the_class;
public:
my_dirty_little_secret(const std::string& str)
{
// however that calculates x, y, and z from str I wouldn't know
}
int x;
std::string y;
float z;
};
class the_class : private my_dirty_little_secret // must be first, see ctor
, public the_other_base_class {
public:
the_class(const std::string str)
: my_dirty_little_secret(str)
, the_other_base_class(x, y, z)
{
}
// ...
};
Класс my_dirty_little_secret
является частной базой, так что пользователи the_class
не могут использовать его, все его материалы также являются частными, а явная дружба предоставляет только the_class
доступ к нему. Однако, поскольку он указан первым в списке базового класса, он будет надежно создан до the_other_base_class
, поэтому все, что он рассчитывает, может быть использован для инициализации этого.
Хороший комментарий в списке базового класса, надеюсь, не позволяет другим нарушать вещи путем рефакторинга.
Ответ 3
IMHO Я не думаю, что можно отложить вызов конструктора базового класса так, как вы упомянули.
Ответ 4
Вау, мы все были молодыми однажды. Этот ответ не будет работать, поэтому не используйте его. Содержание осталось в исторических целях.
Если у вас есть полный контроль над базовым классом, я бы рекомендовал добавить защищенный метод для инициализации класса, сделать его виртуальным и поместить в него детали реализации производного класса, прежде чем он назовет его базу:
class Base
{
public:
Base()
{
Initialize();
}
protected:
virtual void Initialize()
{
//do initialization;
}
};
class Derived : Base
{
public:
Derived() : Base()
{
}
protected:
virtual void Initialize()
{
//Do my initialization
//call base
Base::Initialize();
}
};
Ответ 5
struct base{
base(int x){}
};
struct derived : base{
derived(int x) : base(x){}
};
Вот как конструкторы базового класса вызывается в С++ из списка инициализации производного класса.