Унаследованный класс, инициализирующий пользовательский класс с использованием конструктора не по умолчанию
Так что я искал повсюду, и я не могу найти ответ на этот конкретный вопрос. Я использую WinXP с Cygwin и GCC 3.4.4 Cygming Special.
Проблема: у меня есть класс, который работает как интерфейс с некоторыми абстрактными методами и защищенными переменными, которые должны быть в каждом классе, который наследуется от этого класса. Теперь у меня также есть другой класс, который является переменной-членом этого интерфейса.
class Bar {
private:
int y;
public:
Bar(int why);
};
Bar::Bar(int why) : y(why) {}
class Foo {
protected:
Bar b;
public:
Foo(int x);
virtual void print_base();
};
Foo::Foo(int x) : b(x+3) // Have to use initializer list here.
{
//this->b(x+3); // doesn't work
}
class DerFoo : public Foo {
protected:
Bar db;
public:
DerFoo(int x);
};
DerFoo::DerFoo(int x) : Foo(x),
db(x+3) // (Bar)(int) being called, works fine
// db(4.0, 30) // no matching function for call to Bar::Bar(double, int)
// note: candidates are Bar::Bar(const Bar&), Bar::Bar(int)
// b(x-3) // doesn't work class DerFoo does not have any field named 'b'
{
//this->b(x - 3); // Doesn't work, error no match for call to (Bar)(int)
//this->db(x + 3); // Doesn't work, error no match for call to (Bar)(int)
}
Таким образом, проблема, как вы можете видеть, находится внутри производного класса foo, DerFoo, как инициализировать b. Я пробовал метод инициализации члена, но затем компилятор не понимает о защищенных переменных. Итак, по какой-то причудливой причине, незаметной для меня, он не может найти конструктор в этом классе. Даже если бы включить "неправильный" вызов в конструктор защищенной переменной-члена (не наследуемой), он предложил бы правильную версию конструктора.
Я понятия не имею, как это сделать. Любая помощь с благодарностью.
5 ответов
DerFoo
Конструкторы не должны (и не могут) инициализироваться b
, это Foo
работа. DerFoo
конструкторы отвечают только за инициализацию DerFoo
непосредственные подобъекты, а именно db
и Foo
который является базовым классом DerFoo
, Foo
конструктор, в свою очередь, отвечает за инициализацию b
,
Последовательность событий выглядит так:
DerFoo
конструктор вызываетFoo
конструкторFoo
конструктор вызываетb
конструкторFoo
конструктор запускает свое тело, оставляяFoo
объект полностью построенDerFoo
конструктор invoke'sdb
конструкторDerFoo
конструктор запускает свое тело, оставляяDerFoo
Объект полностью построен.
Если в DerFoo
конструктор, вам не нравится значение, которое Foo
конструктор оставил в b
Вы можете назначить новое значение b
используя любой из этих синтаксисов:
b = Bar(47);
this->b = Bar(47);
this->Foo::b = Bar(47);
Foo::b = Bar(47);
После того, как вы объявите переменную, вы должны будете установить ее, иначе вы будете вызывать ее как функцию.
this->b = Bar(x+3);
Предпочтительным способом является использование списка инициализаторов, чтобы избежать ненужных копий Bar
, Однако если вам нужно установить b вне конструктора, приведенный выше пример показывает, как это сделать.
Я не нахожу вопрос очень ясным, но давайте посмотрим, понял ли я, что вы пытаетесь сделать и как.
DerFoo::DerFoo(int x) : Foo(x), [a]
db(x+3)
// db(4.0,30) [1]
// note: candidates are Bar::Bar(const Bar&), Bar::Bar(int)
// b(x-3) [2]
{
//this->b(x - 3); [3]
//this->db(x + 3); [4]
}
Первая ошибка [1], где компилятор говорит вам, что нет конструктора Bar
это занимает как двойной, так и int. В ошибке также перечислены два возможных конструктора, которые вы можете использовать: Bar(int)
, Bar(Bar const &)
, Я не уверен в том, что вы намеревались с этой строкой, но вы уже выяснили (предыдущая строка), что просто предоставив int
звонок будет работать.
[2] b
не является членом DerFoo
и, следовательно, не может быть инициализирован в списке инициализатора DerFoo
, Это ответственность Foo
инициализировать свой собственный член, и это произойдет через вызов к Foo
конструктор в [a].
[3], [4] оба выражения принимают вид this->member(i)
, Во время инициализации синтаксиса member(i)
будет хорошо, инициализировать member
со значением i
, Вне инициализации синтаксис означает вызов operator()( int )
передавая значение i
, Эти элементы уже инициализированы, но если вы хотите сбросить их, вам нужно назначить, а не инициализировать их.
b
находится внутри класса Foo. чтобы получить к нему доступ (наверняка)
Foo::b = Bar(x-3);
Вам не нужно использовать список инициализаторов, вам определенно также следует использовать список инициализаторов на этом этапе.
При построении объекта перед вводом кода конструктора все переменные-члены уже созданы. Если вы не дадите инициализаторы, они будут созданы по умолчанию.
Также вы не можете создать переменную снова, после того, как она уже была создана. Ваш
this->b(x+3)
не говорит компиляции, чтобы построить b
он говорит, чтобы вызвать функцию с именем b
на вашем объекте. Такая функция не существует в вашем классе, следовательно, ошибка. Обратите внимание, что после того, как объект был сконструирован в переменную, уже невозможно снова вызвать конструктор для этой переменной (только для изменения значения).
Значение можно изменить с помощью =
как в большинстве языков. Следовательно, вы можете сделать:
Foo::Foo(int x)
{
this->b = Bar(x+3);
}
Это означает, что вы создаете еще одно безымянное Bar
объект и присвоение его значения this->b
, Вы должны знать, что это означает, что вы создадите два Bar
объекты, при создании Foo
, Сначала созданный по умолчанию, прежде. Вводится код конструктора, затем новый безымянный. Затем вы, наконец, присвойте значение уже сконструированному объекту, так что этот код гораздо более неэффективен, чем тот, который использует списки инициализаторов.
РЕДАКТИРОВАТЬ:
Так как я пропустил второй doesn't work
в приведенном выше коде приведена дополнительная информация:
Вы также пытаетесь инициализировать b
непосредственно в конструкторе производного DerFoo
объект. Однако, как только эта часть кода достигнута, она уже создана. Следовательно, любая попытка построить его в производном конструкторе запаздывает.
Следовательно, вы должны либо добавить еще один конструктор Foo
который принимает значение и использовать его в конструкторе DerFoo
, Это решение является предпочтительным, так как оно построит только Bar
объект в b
один раз. Если вы не можете добавить такой конструктор, вам нужно использовать присваивание в коде конструктора для DerFoo
,
Попытка инициализировать b
прямо в DerFoo
Конструктор не будет работать, даже если используется оператор области видимости.
DerFoo::DerFoo() : Foo::b(x-3) {}
все равно выдаст ошибку: http://ideone.com/6H8ZD