Я пытаюсь добиться чего-то вроде этого:
class Base
{
public:
Base(string S)
{
...
};
}
class Derived: Base
{
public:
int foo;
string bar()
{
return stringof(foo); // actually, something more complex
};
Derived(int f) : foo(f), Base(bar())
{
};
}
Теперь это работает не так, как я хочу, потому что bar () вызывается в конструкторе Derived перед инициализацией foo.
Я подумал о добавлении статической функции, подобной bar (), которая принимает foo в качестве параметра, и использовании ее в списке инициализации, но подумал, что спрошу, есть ли какие-нибудь другие методы, которые можно было бы использовать, чтобы выбраться из этого. ..
Редактировать: Спасибо за отзыв - вот как я собирался обрабатывать статическую функцию. Не уверен, что перегрузка между статической и нестатической функцией слишком умен, но ...
class Derived: Base
{
public:
int foo;
static string bar(int f)
{
return stringof(f); // actually, something more complex
}
string bar()
{
return bar(foo);
};
Derived(int f) : Base(bar(f)) , foo(f)
{
};
}





Да, использование функции (метода статического класса или обычной функции), которая принимает фу в качестве параметра и возвращает строку, является хорошим решением. Вы можете вызвать эту же функцию из Derived :: bar, чтобы предотвратить дублирование кода. Итак, ваш конструктор будет выглядеть так:
Derived(int f) : Base(stringof(f)), foo(f) {}
Я помещаю вызов конструктора Base первым в списке, чтобы подчеркнуть порядок, в котором происходят инициализации. Порядок списка инициализаторов не имеет никакого эффекта, поскольку все члены класса инициализируются в том порядке, в котором они объявлены в теле класса.
Это очень чистый, функциональный подход к проблеме. Однако, если вы все же хотите взвесить альтернативы, подумайте об использовании состав вместо наследования для отношения между производным и базовым классами:
class Base {
public:
Base(string S) { ... }
void bat() { ... }
};
class Derived {
Base *base;
int foo;
public:
Derived(int f) : base(NULL), foo(f) {
base = new Base(bar());
}
~Derived() {
delete base;
}
string bar() {
return stringof(foo); // actually, something more complex
}
void bat() {
base->bat();
}
};
Вам нужно будет рассмотреть плюсы и минусы для вашей конкретной ситуации. Когда Derived содержит ссылку на Base, вы получаете больший контроль над порядком инициализации.
Приятно - однако обратная сторона композиции - это количество заглушек, похожих на летучую мышь, необходимых для раскрытия базовых методов.
Правда! Я подумал, что в данном случае вы будете придерживаться плана А именно по этой причине.
Я тоже хотел это сделать, но в конце концов сдался.
В качестве параметра Base () можно использовать любой подходящий вызов функции.
Другой вариант - добавить в Base альтернативный конструктор, который принимает int и выполняет преобразование в строку.
«Альтернативный конструктор» неприятен, потому что логика преобразования по сути является частью производного класса.
Что ж, я догадывался, что это так, но это была единственная альтернатива статической функции, которую я мог придумать.
Вы можете вызывать только статические функции в списке инициализаторов. То, как это есть в вашем коде:
class Derived: Base
{
public:
int foo;
string bar()
{
return stringof(foo); // actually, something more complex
};
Derived(int f) : foo(f), Base(bar())
{
};
}
По-прежнему инициализирует сначала Base, а затем foo. Порядок написания вещей в списке инициализаторов конструктора никоим образом не имеет значения. Он всегда будет строиться в таком порядке:
Таким образом, вы в конечном итоге вызываете stringof с неинициализированным значением. Эта проблема решена в boost::base_from_member. Также обратите внимание, что вызов любой нестатической функции-члена до завершения всех инициализаторов конструктора всех базовых классов является неопределенным поведением.
Однако вызов статических функций - это нормально:
class Derived: Base
{
public:
int foo;
static string bar(int f)
{
return stringof(f); // actually, something more complex
};
Derived(int f) : Base(bar(f)), foo(f)
{
};
}
Конструктор базового класса всегда вызывается перед инициализацией других членов производного класса; ваш компилятор должен предупреждать вас о неправильном порядке инициализаторов. Единственное правильное решение - сделать bar() статическим методом, который принимает f в качестве параметра.
Конструктор предназначен для создания объекта. Это означает, что до тех пор, пока он не вернется, там нет объекта, и поэтому вызывающие функции-члены просто не будут работать надежно. Как говорят все, используйте статическую функцию или функцию, не являющуюся членом.
Не совсем так, потому что конструкторы обычно вызывают нестатические методы - например, «init ()». Списки инициализации немного отличаются.
Просто переместите код конструктора в функцию Initialize () и вызовите ее из конструктора. Это намного проще, чем статическое / нестатическое переопределение или что-то в этом роде.
вы упускаете суть. базовый класс не может быть сконструирован правильно так, как вы описываете.
хм, комбинировать это с идиомой pimpl было бы неплохо