在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设置不同的值,但已知这些值在实例的生存期内是恒定的。

有了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;
}

正如其他人所说,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++0x中做到这一点(请参阅Bjarne Stroustrup的《C++0x简介》,了解有关初始值设定值列表和其他不错的C++0x功能的更多信息)。

std::vector使用堆。天啊,仅仅为了const的健全性检查,这是多么浪费啊。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("%dn", b.Array()[i]);
        }
    }
};

int main()
{
    a x;
    x.print_items();
    return 0;
}

CCD_ 6和CCD_。

第一种方法允许在初始化数组时进行运行时边界检查(与向量一样),在初始化之后,数组可以变为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 << "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不受成员函数的影响。这可以通过继承;但我想我更喜欢John Harrison的comp.lang.c++使用const类的帖子。

有趣的是,在C#中,关键字const可以转换为C++的静态const,而只读只能在构造函数和初始化时设置,甚至可以由非常量设置,例如:

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,但我不喜欢这种方法,我在标题的末尾使用#unde,并在CPP处编辑一条注释,以防发生更改。

相关内容

  • 没有找到相关文章

最新更新