инициализация массива const в инициализаторе класса В C++
у меня есть следующий класс В C++:
class a {
const int b[2];
// other stuff follows
// and here's the constructor
a(void);
}
вопрос в том, как инициализировать b в списке инициализации, учитывая, что я не могу инициализировать его внутри тела функции конструктора, потому что b является const
?
это не работает:
a::a(void) :
b([2,3])
{
// other initialization stuff
}
изменить: дело в том, когда я могу иметь разные значения для b
для разных экземпляров, но известно, что значения постоянны в течение всего срока службы экземпляра.
10 ответов
как говорили другие, ISO C++ не поддерживает это. Но вы можете обойти это. Просто используйте std::vector вместо этого.
int* a = new int[N];
// fill a
class C {
const std::vector<int> v;
public:
C():v(a, a+N) {}
};
С C++11 ответ на этот вопрос теперь изменился, и вы можете фактически сделать:
struct a {
const int b[2];
// other bits follow
// and here's the constructor
a();
};
a::a() :
b{2,3}
{
// other constructor work
}
int main() {
a a;
}
Это невозможно в текущем стандарте. Я считаю, что вы сможете сделать это в C++0x, используя списки инициализаторов (см. краткий взгляд на C++0x, Bjarne Stroustrup, для получения дополнительной информации о списках инициализаторов и других приятных функциях C++0x).
std::vector
использует кучу. Боже, что за пустая трата времени только ради ... --2--> вменяемость проверить. Смысл std::vector
динамический рост во время выполнения, а не любая старая проверка синтаксиса, которая должна выполняться во время компиляции. Если вы не собираетесь расти, создайте класс для обертывания обычного массива.
#include <stdio.h>
template <class Type, size_t MaxLength>
class ConstFixedSizeArrayFiller {
private:
size_t length;
public:
ConstFixedSizeArrayFiller() : length(0) {
}
virtual ~ConstFixedSizeArrayFiller() {
}
virtual void Fill(Type *array) = 0;
protected:
void add_element(Type *array, const Type & element)
{
if(length >= MaxLength) {
// todo: throw more appropriate out-of-bounds exception
throw 0;
}
array[length] = element;
length++;
}
};
template <class Type, size_t Length>
class ConstFixedSizeArray {
private:
Type array[Length];
public:
explicit ConstFixedSizeArray(
ConstFixedSizeArrayFiller<Type, Length> & filler
) {
filler.Fill(array);
}
const Type *Array() const {
return array;
}
size_t ArrayLength() const {
return Length;
}
};
class a {
private:
class b_filler : public ConstFixedSizeArrayFiller<int, 2> {
public:
virtual ~b_filler() {
}
virtual void Fill(int *array) {
add_element(array, 87);
add_element(array, 96);
}
};
const ConstFixedSizeArray<int, 2> b;
public:
a(void) : b(b_filler()) {
}
void print_items() {
size_t i;
for(i = 0; i < b.ArrayLength(); i++)
{
printf("%d\n", b.Array()[i]);
}
}
};
int main()
{
a x;
x.print_items();
return 0;
}
ConstFixedSizeArrayFiller
и ConstFixedSizeArray
многоразовые.
первый позволяет проверять границы времени выполнения при инициализации массива (так же, как и вектор), который может позже стать const
после этой инициализации.
второй позволяет массиву быть выделенным внутри другой объект, который может быть в куче или просто стеке, если это то, где находится объект. Нет никакой траты времени, выделяя из кучи. Он также выполняет проверку const во время компиляции массива.
b_filler
- это крошечный частный класс для предоставления значений инициализации. Размер массива проверяется во время компиляции с помощью шаблонов аргументы, так что нет никаких шансов выйти за рамки.
Я уверен, что есть более экзотические способы, чтобы изменить это. Это первый удар. Я думаю, вы можете в значительной степени компенсировать любой из недостатков компилятора с классами.
стандарт ISO C++ не позволяет вам это делать. Если бы это было так, синтаксис, вероятно, был бы:
a::a(void) :
b({2,3})
{
// other initialization stuff
}
или что-то в этом роде. Из вашего вопроса на самом деле звучит так, что вы хотите, это постоянный член класса (он же статический), который является массивом. C++ позволяет вам это делать. Вот так:
#include <iostream>
class A
{
public:
A();
static const int a[2];
};
const int A::a[2] = {0, 1};
A::A()
{
}
int main (int argc, char * const argv[])
{
std::cout << "A::a => " << A::a[0] << ", " << A::a[1] << "\n";
return 0;
}
выход быть:
A::a => 0, 1
теперь, конечно, поскольку это статический член класса, он одинаков для каждого экземпляра класса A. Если это не то, что вы хотите, т. е. вы хотите, чтобы каждый экземпляр A имел разные значения элементов в массиве a, тогда вы делаете ошибку, пытаясь сделать массив const для начала. Вы должны просто делать это:
#include <iostream>
class A
{
public:
A();
int a[2];
};
A::A()
{
a[0] = 9; // or some calculation
a[1] = 10; // or some calculation
}
int main (int argc, char * const argv[])
{
A v;
std::cout << "v.a => " << v.a[0] << ", " << v.a[1] << "\n";
return 0;
}
где у меня есть постоянный массив, он всегда был сделан как статический. Если вы можете принять это, этот код должен компилироваться и запускаться.
#include <stdio.h>
#include <stdlib.h>
class a {
static const int b[2];
public:
a(void) {
for(int i = 0; i < 2; i++) {
printf("b[%d] = [%d]\n", i, b[i]);
}
}
};
const int a::b[2] = { 4, 2 };
int main(int argc, char **argv)
{
a foo;
return 0;
}
вы не можете сделать это из списка инициализации,
взгляните на это:
http://www.cprogramming.com/tutorial/initialization-lists-c++.html
:)
решение без использования кучи с std::vector
использовать boost::array
, хотя вы не можете инициализировать элементы массива непосредственно в конструкторе.
#include <boost/array.hpp>
const boost::array<int, 2> aa={ { 2, 3} };
class A {
const boost::array<int, 2> b;
A():b(aa){};
};
Как насчет эмуляции массива const с помощью функции доступа? Это нестатический (как вы просили), и он не требует stl или любой другой библиотеки:
class a {
int privateB[2];
public:
a(int b0,b1) { privateB[0]=b0; privateB[1]=b1; }
int b(const int idx) { return privateB[idx]; }
}
поскольку a:: privateB является частным, он фактически постоянен вне a::, и вы можете получить к нему доступ, подобный массиву, например
a aobj(2,3); // initialize "constant array" b[]
n = aobj.b(1); // read b[1] (write impossible from here)
Если вы хотите использовать пару классов, вы можете дополнительно защитить privateB от функций-членов. Это может быть сделано путем наследования; но я думаю, что я предпочитаю комп Джона Харрисона.ленг.сообщение c++ с использованием класса const.
интересно, что в C# у вас есть ключевое слово const, которое переводится в статический const C++, в отличие от readonly, который может быть установлен только в конструкторах и инициализациях, даже не-константами, например:
readonly DateTime a = DateTime.Now;
Я согласен, если у вас есть заранее определенный массив const, вы можете также сделать его статическим. В этот момент Вы можете использовать этот интересный синтаксис:
//in header file
class a{
static const int SIZE;
static const char array[][10];
};
//in cpp file:
const int a::SIZE = 5;
const char array[SIZE][10] = {"hello", "cruel","world","goodbye", "!"};
однако я не нашел способа обойти константу "10". Причина ясна, хотя, она должна знать как выполнить доступ к массиву. Возможной альтернативой является использование #define, но мне не нравится этот метод и I #undef в конце заголовка, с комментарием Для редактирования там в CPP, а также в случае изменения.