инициализация константного члена базового класса в производный класс - PullRequest
2 голосов
/ 27 сентября 2011
public:
    const int x;
    base():x(5){}

};

class der : public base {
public:
    der():x(10){}
};

der d;

Моя цель состоит в том, чтобы при создании экземпляра базового класса он инициализировал x как 5, а при создании экземпляра der class он инициализировал x как 10. Но компилятор выдает ошибку.Поскольку x наследуется от базы классов, почему он дает ошибку?

Ответы [ 4 ]

7 голосов
/ 27 сентября 2011

Вы можете выполнить эту работу с небольшой корректировкой ...

#include <cassert>

class base
{
public:
    const int x;
    base()
        :x(5)
    {
    }

protected:
    base(const int default_x)
        :x(default_x)
    {
    }
};

class der: public base
{
public:
    der()
        :base(10)
    {
    }
};

struct der2: public base
{
    der2()
        :base()
    {
    }
};

int main()
{
    base b;
    assert(b.x == 5);
    der d;
    assert(d.x == 10);
    der2 d2;
    assert(d2.x == 5);
    return d.x;
}

Это обеспечивает конструктор, доступный производным классам, который может предоставить значение по умолчанию, с помощью которого можно инициализировать base.x.

5 голосов
/ 27 сентября 2011

Вы не можете инициализировать член базового класса в списке инициализатора для конструктора в производном классе. Список инициализаторов может содержать базы и члены этого класса, но не члены в базах.

По общему признанию, стандарт для этого не совсем ясен. 12.6.2 / 2 из C ++ 03:

Если только в mem-initializer-id не указан нестатический элемент данных класс конструктора или прямая или виртуальная база этого класса, mem-инициализатор плохо сформирован.

Это означает «(нестатический член данных класса конструктора) или (прямая или виртуальная база)». Это не означает «нестатический член данных (класс конструктора или прямая или виртуальная база)». Предложение двусмысленное, но если вы взяли второе чтение, вы вообще не сможете поместить базы в список инициализаторов, а следующее предложение в стандарте проясняет, что вы можете.

Что касается того, почему это не разрешено, это стандартный вопрос обоснования, и я предполагаю мотивы авторов стандарта. Но в основном потому, что ответственность за инициализацию своих собственных членов лежит на базовом классе, а не ответственность производного класса.

Возможно, вам следует добавить int конструктор к base.

1 голос
/ 27 сентября 2011

Это работает.

class base {
public:
    static const int x = 5;
};

class der : public base {
public:
    static const int x = 10;
};

Если вы хотите изменить x в зависимости от вашего конструктора, вы должны сделать его нестатичным.

Нестатическая константа - это то же самое, что и неконстантная переменная после компиляции. Если вы хотите, чтобы переменная-член была доступна только для чтения, используйте нестатический const. Если вы хотите установить константу, область действия которой ограничена одним классом, используйте static const.

0 голосов
/ 27 сентября 2011

Это может быть слишком сложным по сравнению с первоначальным вопросом, но, пожалуйста, учтите:

template <typename T, class C, int index=0> 
// C and index just to avoid ambiguity
class constant_member {
    const T m;
    constant_member (T m_) :m(m_) {}
};

class base : virtual public constant_member<int, base> {
public:
    base () : constant_member<int, base>(5) {}
    int x () const { return constant_member<int, base>::m; }
};

class der : public base {
public:
    der () : constant_member<int, base>(10) {}
};

class der2 : public der{
public:
    der2 () {} // ill-formed: no match for 
               // constant_member<int, base>::constant_member() 
};

Комментарий: это многословно, неочевидно (возможно, невозможно понять для начинающих), и это будет оченьнеэффективно преобразовывать в virtual базовый класс только для чтения переменной-члена.Я не действительно предлагаю это как реальное решение для мира.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...