2010-06-16 3 views
3

Я хочу инициализировать константу в классе child вместо базового класса. И используйте его, чтобы избавиться от динамического распределения памяти (я уже знаю размеры массива, и будет несколько дочерних классов с разными константами).
Так что я стараюсь:Константы инициализации C++ и наследование

class A { 
public: 
    const int x; 

    A() : x(0) {} 
    A(int x) : x(x) {} 
    void f() { 
     double y[this->x]; 
    } 
}; 

class B : A { 
    B() : A(2) {} 
}; 

Довольно простой, но компилятор говорит:

ошибка C2057: ожидается постоянное выражение

Как я могу сказать компилятору, что это действительно постоянная?

+2

Это не постоянное выражение, если его значение определено во время выполнения. Подумайте об этом так: постоянное выражение постоянное, что означает, что размер массива будет постоянным во всех A. Тем не менее, вам нужны разные размеры по A. Разный размер -> Не постоянный. – GManNickG

ответ

4

Это не постоянное, хотя. Он может быть изменен конструктором. Для размера массива допускается только время компиляции. Когда компилятор говорит «постоянное выражение», это не означает выражение, которое возвращает постоянное значение, а константу, например «52» или «45» или что-то в этом направлении.

Вместо этого использовать std::vector.

EDIT: В ответ на «Я знаю, что размеры массива уже, и там будет несколько дочерних классов с различными константами»

Единственный способ сделать это заключается в использовании шаблона.

template<size_t x> 
class A { 
public: 
    void f() { 
     double y[x]; 
    } 
}; 

typedef A<2> B; 
2

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

Обратите внимание, что это на самом деле ненадежно, отвратительно и может использоваться только как «образец». Вместо этого используйте std::vector.

template <size_t a = 0> 
class A { 
public: 
    A() { } 

    void f() { 
     int y[a]; 
     y[0] = 5; 
    } 
}; 

class B : A<2> { 
    B() { } 
}; 

void main() { 
    A<1> a; 
    a.f(); 

    // Undefined behaviour - creating an array of size 0 
    // At least, MSVS2008 treats it as an error :) 
    // A<0> a_; 
} 
+0

Gah; избили четыре секунды! – strager

+0

Не уверен, что такая хорошая идея позволяет отрицательные значения. (Используйте неподписанный интегральный тип, такой как size_t, а не int) –

+1

Как «// Ошибка здесь!» Вызывает ошибку?Во всяком случае, это просто неопределенное поведение на 'y [0] = 5;'. – strager

1

Там в "постоянный", а есть "постоянный". Если вы хотите выделить такой массив в стеке, компилятору требуется длина массива во время компиляции, и в зависимости от того, что вы там дали, он не может понять это. Интересно, что gcc поддерживает расширение (не поддерживается в стандартном C++), которое позволяет распределять стеки для переменной длины.

+0

Причина, по которой GCC поддерживает это, - это функция C99, не дублируемая C++. C++ 0x не добавлял эту функцию, потому что у C++ есть 'vector', что делает полезностью массива переменной длины nill. –

1

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

template <int size> 
class A { 
    double y[size]; 
}; 

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

Другой очевидной возможностью было бы использовать объект tr1::array. Это также шаблон, поэтому идея почти такая же, но она уже написана, протестирована и работает, поэтому вы можете избежать всего этого. Если ваш компилятор не предоставляет классы TR1, Boost имеет в основном соответствующую реализацию (boost::array).