Как я могу инициализировать параметры суперкласса из дочернего c-tor в C++?

Посмотрите следующий пример:

class A {
public:
    A(int param1, int param2, int param3) {
        // ...
    }
};

class B : public A {
public:
    B() : m_param1(1), m_param(2), m_param(3), A(m_param1, m_param2, m_param3) {
        // ...
    }
};

B b;

Очевидно, что когда будет создан "b", ctor A будет вызван до того, как будут инициализированы параметры B.

Это правило не позволяет мне создавать классы-оболочки, которые упрощают инициализацию класса.

Каков "правильный способ" для этого?

Спасибо, Амир

PS: В моем конкретном случае параметры не являются примитивами, этот пример просто помог мне объясниться.


person Amir    schedule 14.11.2010    source источник
comment
Я понимаю проблему. Однако похоже, что вы дублируете информацию. Почему вы оказались в ситуации, когда вам нужно инициализировать A и B с одинаковыми параметрами?   -  person Oliver Charlesworth    schedule 15.11.2010
comment
В частности, я использую библиотеку физики Bullet, которая принимает указатели на объекты в качестве параметров. Я хочу создать и сохранить объект в дочернем классе и передать его указатель суперклассу. Благодаря этому я могу создать класс символов, который наследуется от класса физических объектов библиотеки.   -  person Amir    schedule 15.11.2010
comment
я не уверен, что понял вопрос, но помните одну вещь - операторы в списке инициализации не выполняются в указанном вами порядке, они выполняются в том порядке, в котором базовые классы и переменные-члены указаны в объявлении класса.   -  person Janusz Lenar    schedule 15.11.2010
comment
... и именно поэтому ответ Moo-Juice rox :]   -  person Janusz Lenar    schedule 15.11.2010
comment
вы можете передать базу указатель на элемент дочернего элемента, который еще не был инициализирован, просто вы не так много можете сделать с этим указателем до инициализации (например, вы не можете привести его к указателю на один из его базовые классы). 3.8/5 в стандарте указывает это.   -  person Steve Jessop    schedule 15.11.2010


Ответы (3)


«Параметры не являются примитивами». Так у вас есть что-то подобное?

class Param { /*...*/ };
class A {
public:
  A(const Param& param1, const Param& param2, const Param& param3);
};

class B : public A {
public:
  B();
private:
  Param m_param1;
  Param m_param2;
  Param m_param3;
};

И вы хотите передать элементы B конструктору A. Как насчет этого?

class B_params {
protected:
  B_params(int v1, int v2, int v3);
  Param m_param1;
  Param m_param2;
  Param m_param3;
};
class B : private B_params, public A {
public:
  B();
};

B_params::B_params(int v1, int v2, int v3)
  : m_param1(v1), m_param2(v2), m_param3(v3) {}
B::B() : B_params(1,2,3), A(m_param1, m_param2, m_param3) {}

Просто убедитесь, что B_params стоит перед A в списке унаследованных классов B.

person aschepler    schedule 14.11.2010
comment
Я уже знал этот метод, но предпочитаю не использовать множественное наследование. Я, вероятно, воспользуюсь этим методом, потому что я вижу любое другое решение, кроме этого и шаблона проектирования Factory. Я просто подожду еще немного, чтобы увидеть, появится ли лучшее решение. - person Amir; 15.11.2010

Просто вызовите конструктор A:

class B : public A
{
public:
    B() : A(1 ,2, 3)
    {
    }; // eo ctor
}; // eo class B

ИЗМЕНИТЬ:

Просто прочитайте свой комментарий к исходному сообщению. Важно четко понимать эти вещи :) В любом случае, этот ответ остается верным, если вы хотите создавать новые данные в B, отслеживать их в B, и передавать их в A:

class Object
{
private:
    int i;
public:
    Object(int _i) : i(_i){};
};

class A
{
public:
    A(Object* _1, Object* _2, Object* _3)
    {
    };
};

class B : public A
{
private:
    Object* _1;
    Object* _2;
    Object* _3;

public:
    B() : A(_1 = new Object(1), _2 = new Object(2), _3 = new Object(3))
    {
    };
};
person Moo-Juice    schedule 14.11.2010
comment
вы уверены, что B::_1 и т. д. не будут аннулированы после вызова A(Object*,...)? - person Janusz Lenar; 15.11.2010
comment
Нет причин, почему это должно быть, объект (на данный момент) был выделен. Я тестировал вышеизложенное на VS2010, поэтому не могу комментировать другие компиляторы. Я не понимаю, почему это может быть проблемой. - person Moo-Juice; 15.11.2010
comment
подумайте о B():_1(new Object(1)),_2(new Object(2)),_3(new Object(3)),A(_1,_2,_3){}. это испортится из-за фактического порядка выполнения. на самом деле важно, что это просто работает :] - person Janusz Lenar; 15.11.2010
comment
@Janusz: Это так :) Выражения будут оцениваться до вызова конструктора A. Это позволяет нам как размещать наши объекты, так и назначать их нашим членам, И передавать их базовому классу. - person Moo-Juice; 15.11.2010
comment
да, ваш пример rox, правда :) теперь мне интересно, если стандартные запрещают компиляторам автоинициализацию членов. здесь, если компилятор недостаточно умен, он может обнулить _1, _2 и _3 сразу после вызова ctor A, когда пришло время их инициализировать. ты понимаешь мою точку зрения? :) - person Janusz Lenar; 15.11.2010
comment
Хм. Если член типа POD (который включает в себя все указатели) не указан в списке mem-initializer конструктора, этот член не инициализируется. Я предполагаю, что это позволяет делать такие вещи, которые присваиваются им раньше, чем это сделал бы мем-инициализатор. (Но если тип члена является классом с конструктором, этот метод, конечно, не будет работать.) - person aschepler; 15.11.2010
comment
спасибо, ашеплер. это следует упомянуть, поскольку здесь вполне разумно использовать std::auto_ptr. - person Janusz Lenar; 15.11.2010

Не уверен, что понял ваш вопрос.

Если вам просто нужно что-то, что поможет вам инициализировать A с некоторыми заданными параметрами, вы должны использовать конструктор A со значениями по умолчанию:

class A {
public:
    A(int param1 = 1, int param2 = 2, int param3 =3) {
        // ...
    }
};
person peoro    schedule 14.11.2010
comment
Нет, А — заданный класс, который я должен упростить. - person Amir; 15.11.2010