Унаследованный класс, инициализирующий пользовательский класс с использованием конструктора не по умолчанию - PullRequest
2 голосов
/ 29 марта 2012

Так что я искал повсюду, и я не могу найти ответ на этот конкретный вопрос.Я использую winXP с cygwin и gcc 3.4.4 special cygming.

Проблема: у меня есть класс, который работает как интерфейс с некоторыми абстрактными методами и защищенными переменными, которые должны быть в каждом классе, который наследуется от этого класса,Теперь у меня также есть другой класс, который является переменной-членом этого интерфейса.

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 ]

3 голосов
/ 29 марта 2012

После того, как вы объявите переменную, вы должны установить ее, иначе вы будете вызывать ее как функцию.

this->b = Bar(x+3);

Предпочтительным способом является использование списка инициализаторов, чтобы избежать ненужных копий Bar. Однако если вам нужно установить b вне конструктора, приведенный выше пример показывает, как это сделать.

2 голосов
/ 29 марта 2012

DerFoo конструкторы не должны (и не могут) инициализировать b, это Foo задание.Конструкторы DerFoo отвечают за инициализацию только непосредственных подобъектов DerFoo, а именно db и Foo, который является базовым классом DerFoo.Конструктор Foo, в свою очередь, отвечает за инициализацию b.

Последовательность событий имеет вид:

  • DerFoo вызывает конструктор Fooконструктор
  • Foo конструктор вызывает b конструктор
  • Foo конструктор запускает свое тело, оставляя объект Foo полностью построенным
  • DerFoo конструктор вызывает db конструктор
  • DerFoo конструктор запускает свое тело, оставляя объект DerFoo полностью построенным.

Еслив конструкторе DerFoo вам не нравится значение, оставленное конструктором Foo в b, вы можете назначить новое значение для b, используя любой из этих синтаксисов:

b = Bar(47);
this->b = Bar(47);
this->Foo::b = Bar(47);
Foo::b = Bar(47);
1 голос
/ 29 марта 2012

Я не нахожу вопрос очень ясным, но давайте посмотрим, понял ли я, что вы пытаетесь сделать и как.

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, который принимает как double, так и 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. Эти члены уже инициализированы, но если вы хотите сбросить их, вам нужно назначить , а не инициализировать их.

0 голосов
/ 29 марта 2012

У вас нет для использования списка инициализаторов, вы определенно также должны использовать список инициализаторов на этом этапе.

При построении объекта, перед вводом кода конструктора все переменные-члены уже построены. Если вы не дадите инициализаторы, они будут созданы по умолчанию.

Также вы не можете снова создать переменную после того, как она уже была создана. Ваш

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

0 голосов
/ 29 марта 2012

b находится внутри класса Foo.чтобы получить к нему доступ (наверняка) используйте

Foo::b = Bar(x-3);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...