Унаследованный класс, инициализирующий пользовательский класс с использованием конструктора не по умолчанию

Так что я искал повсюду, и я не могу найти ответ на этот конкретный вопрос. Я использую 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's dbконструктор
  • 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

Другие вопросы по тегам