在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
不同的实例,但值已知是实例的生命周期不变。
像其他人说的那样,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() { aa; }
目前的标准是不可能的。 我相信你可以在C ++ 0x中使用初始化器列表来完成这个工作(参见Bjarne Stroustrup的C ++ 0x简介 ,了解关于初始化器列表和其他很好的C ++ 0x特性的更多信息)。
std::vector
使用堆。 哎呀,真正的健康检查只是浪费。 std::vector
在运行时是dynamic增长的,而不是在编译时应该做的任何旧的语法检查。 如果你不会增长,那么创build一个类来包装一个普通的数组。
#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() { ax; x.print_items(); return 0; }
ConstFixedSizeArrayFiller
和ConstFixedSizeArray
是可重用的。
第一个允许运行时边界检查,同时初始化数组(与vector相同),在初始化之后,该数组可以稍后变为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中有不同的元素值,那么你正在试图使数组开始的错误。 你应该这样做:
#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 << "va => " << va[0] << ", " << va[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; }
不使用std::vector
堆的解决scheme是使用boost::array
,尽pipe不能直接在构造函数中初始化数组成员。
#include <boost/array.hpp> const boost::array<int, 2> aa={ { 2, 3} }; class A { const boost::array<int, 2> b; A():b(aa){}; };
有趣的是,在C#中,你可以将关键字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", "!"};
然而,我并没有find一个方法来解决“10”的问题。 原因很明显,它需要知道如何访问数组。 一个可能的select是使用#define,但是我不喜欢这个方法,并且我在头文件尾部加了#undef,并在CPP中编辑注释,以及如果发生改变。
如何通过访问函数来模拟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 aobj(2,3); // initialize "constant array" b[] n = aobj.b(1); // read b[1] (write impossible from here)
如果你愿意使用一对类,你还可以保护privateB免于成员函数。 这可以通过inheritance一个; 但我想我更喜欢使用const类的John Harrison的comp.lang.c ++文章。