2008-10-02 5 views
65

У меня есть следующий класс в C++:инициализировать константный массив в классе инициализаторе в C++

class a { 
    const int b[2]; 
    // other stuff follows 

    // and here's the constructor 
    a(void); 
} 

Вопрос заключается в том, как я инициализировать б в списке инициализации, учитывая, что я не могу инициализировать внутри тела функции конструктора, потому что b равно const?

Это не работает:

a::a(void) : 
    b([2,3]) 
{ 
    // other initialization stuff 
} 

Edit: Дело в точке, когда я могу иметь различные значения для b для различных случаев, но значения, как известно, быть постоянным в течение всего срока службы экземпляра ,

ответ

29

Как и другие, ISO C++ не поддерживает это. Но вы можете обойти это. Вместо этого используйте std :: vector.

int* a = new int[N]; 
// fill a 

class C { 
    const std::vector<int> v; 
public: 
    C():v(a, a+N) {} 
}; 
25

Это не представляется возможным в текущем стандарте. Я считаю, что вы сможете сделать это в C++ 0x, используя списки инициализаторов (см. A Brief Look at C++0x, Bjarne Stroustrup, для получения дополнительной информации об списках инициализаторов и других приятных функциях C++ 0x).

4

Где у меня постоянный массив, это всегда делается как статический. Если вы можете принять это, этот код должен компилироваться и запускаться.

#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; 
} 
+1

, что предполагает, что я действительно хочу, статический член, но это ISN всегда так. Я мог бы иметь массив const, который имеет разные значения для разных экземпляров класса, но значения никогда не меняются в течение жизненного цикла класса – 2008-10-02 11:48:46

+0

, если ваш конструктор не принимает никаких параметров, тогда все экземпляры будут иметь одинаковые значения. Кроме этого, вы правы. – nus 2010-10-31 12:57:51

+0

«Стандарт ISO C++ не позволяет вам» - это хорошая идея, чтобы указать, какую версию стандарта ISO C++ вы имеете в виду. – mloskot 2012-12-12 16:10:16

8

Стандарт ISO C++ не позволяет вам это делать. Если бы это было так, синтаксис, вероятно, был бы следующим:

a::a(void) : 
b({2,3}) 
{ 
    // other initialization stuff 
} 

Или что-то в этом роде. Из вашего вопроса это на самом деле похоже на то, что вы хотите, это постоянный класс (aka static), который является массивом. 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, тогда вы делаете ошибку, пытаясь создать массив 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; 
} 
+1

Почему ошибка заключается в том, чтобы начать создание массива const? Что делать, если я хочу, чтобы значения оставались неизменными для жизни экземпляра, например, какой-то идентификатор? – 2008-10-02 12:15:21

+0

Тогда вы должны использовать тип перечисления. – orj 2008-10-17 11:06:19

2

интересно, в 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, но мне не нравится этот метод, а я #undef в конце заголовка, с комментарием, чтобы редактировать там на CPP, а также в случае изменения.

12

std::vector использует кучу. Боже, какая трата, которая была бы только ради проверки безопасности. Точка 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.

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

b_filler - это небольшой частный класс, обеспечивающий значения инициализации. Размер массива проверяется во время компиляции с аргументами шаблона, поэтому нет возможности выйти за рамки.

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

3

Решение без использования кучи с 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){}; 
}; 
2

Как насчет эмуляции массива const через функцию доступа? Это не статический (как вы просили), и это не требует СТЛО или любую другую библиотеки:

class a { 
    int privateB[2]; 
public: 
    a(int b0,b1) { privateB[0]=b0; privateB[1]=b1; } 
    int b(const int idx) { return privateB[idx]; } 
} 

Поскольку :: privateB является частным, оно эффективно постоянное вне ::, и вы можете получить доступ к он похож на массив, например

a aobj(2,3); // initialize "constant array" b[] 
n = aobj.b(1); // read b[1] (write impossible from here) 

Если вы хотите использовать пару классов, вы можете дополнительно защитить privateB от функций-членов. Это можно сделать, наследуя a; но я думаю, что я предпочитаю John Harrison's comp.lang.c++ post using a const class.

66

С 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; 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^