在 C++ 中的类初始值设定项中初始化 const 数组

发布于 2024-07-06 17:39:44 字数 386 浏览 9 评论 0原文

我在 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 值,但已知这些值在实例的生命周期内是恒定的。

I have the following class in C++:

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

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

The question is, how do I initialize b in the initialization list, given that I can't initialize it inside the body of the function of the constructor, because b is const?

This doesn't work:

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

Edit: The case in point is when I can have different values for b for different instances, but the values are known to be constant for the lifetime of the instance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

格子衫的從容 2024-07-13 17:39:44

使用 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;
}

With C++11 the answer to this question has now changed and you can in fact do:

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;
}
北风几吹夏 2024-07-13 17:39:44

正如其他人所说,ISO C++ 不支持这一点。 但你可以解决它。 只需使用 std::vector 即可。

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

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

Like the others said, ISO C++ doesn't support that. But you can workaround it. Just use std::vector instead.

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

class C {
  const std::vector<int> v;
public:
  C():v(a, a+N) {}
};
沫尐诺 2024-07-13 17:39:44

在现行标准中这是不可能的。 我相信您将能够使用初始化列表在 C++0x 中执行此操作(请参阅简要介绍参见 C++0x,作者:Bjarne Stroustrup,了解有关初始值设定项列表和其他不错的 C++0x 功能的更多信息)。

It is not possible in the current standard. I believe you'll be able to do this in C++0x using initializer lists (see A Brief Look at C++0x, by Bjarne Stroustrup, for more information about initializer lists and other nice C++0x features).

几度春秋 2024-07-13 17:39:44

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("%d\n", b.Array()[i]);
        }
    }
};


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

ConstFixedSizeArrayFillerConstFixedSizeArray 是可重用的。

第一个允许在初始化数组时进行运行时边界检查(与向量可能相同),初始化后数组可以变成 const。

第二个允许将数组分配到另一个对象内部,该对象可以位于堆上,也可以简单地位于堆栈上(如果对象所在的位置就是堆栈)。 从堆中分配不会浪费时间。 它还对数组执行编译时常量检查。

b_filler 是一个微小的私有类,用于提供初始化值。 数组的大小在编译时使用模板参数进行检查,因此不会超出范围。

我确信还有更奇特的方法可以修改它。 这是初步的刺击。 我认为你几乎可以用类来弥补编译器的任何缺点。

std::vector uses the heap. Geez, what a waste that would be just for the sake of a const sanity-check. The point of std::vector is dynamic growth at run-time, not any old syntax checking that should be done at compile-time. If you're not going to grow then create a class to wrap a normal array.

#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 and ConstFixedSizeArray are reusable.

The first allows run-time bounds checking while initializing the array (same as a vector might), which can later become const after this initialization.

The second allows the array to be allocated inside another object, which could be on the heap or simply the stack if that's where the object is. There's no waste of time allocating from the heap. It also performs compile-time const checking on the array.

b_filler is a tiny private class to provide the initialization values. The size of the array is checked at compile-time with the template arguments, so there's no chance of going out of bounds.

I'm sure there are more exotic ways to modify this. This is an initial stab. I think you can pretty much make up for any of the compiler's shortcoming with classes.

飘过的浮云 2024-07-13 17:39:44

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 的每个实例在array 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;
}

ISO standard C++ doesn't let you do this. If it did, the syntax would probably be:

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

Or something along those lines. From your question it actually sounds like what you want is a constant class (aka static) member that is the array. C++ does let you do this. Like so:

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

The output being:

A::a => 0, 1

Now of course since this is a static class member it is the same for every instance of class A. If that is not what you want, ie you want each instance of A to have different element values in the array a then you're making the mistake of trying to make the array const to begin with. You should just be doing this:

#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;
}
半步萧音过轻尘 2024-07-13 17:39:44

当我有一个常量数组时,它总是以静态方式完成。 如果您可以接受这一点,则该代码应该可以编译并运行。

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

Where I've a constant array, it's always been done as static. If you can accept that, this code should compile and run.

#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;
}
老旧海报 2024-07-13 17:39:44

你不能从初始化列表中做到这一点,

看看这个:

http ://www.cprogramming.com/tutorial/initialization-lists-c++.html

:)

You can't do that from the initialization list,

Have a look at this:

http://www.cprogramming.com/tutorial/initialization-lists-c++.html

:)

看透却不说透 2024-07-13 17:39:44

不使用 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){};
};

A solution without using the heap with std::vector is to use boost::array, though you can't initialize array members directly in the constructor.

#include <boost/array.hpp>

const boost::array<int, 2> aa={ { 2, 3} };

class A {
    const boost::array<int, 2> b;
    A():b(aa){};
};
停滞 2024-07-13 17:39:44

通过访问器函数模拟 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。使用 const 类的 c++ post。

How about emulating a const array via an accessor function? It's non-static (as you requested), and it doesn't require stl or any other library:

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

Because a::privateB is private, it is effectively constant outside a::, and you can access it similar to an array, e.g.

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

If you are willing to use a pair of classes, you could additionally protect privateB from member functions. This could be done by inheriting a; but I think I prefer John Harrison's comp.lang.c++ post using a const class.

摘星┃星的人 2024-07-13 17:39:44

有趣的是,在 C# 中,关键字 const 可以转换为 C++ 的 static const,而不是 readonly,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 处添加注释以进行编辑,以防发生更改。

interestingly, in C# you have the keyword const that translates to C++'s static const, as opposed to readonly which can be only set at constructors and initializations, even by non-constants, ex:

readonly DateTime a = DateTime.Now;

I agree, if you have a const pre-defined array you might as well make it static.
At that point you can use this interesting syntax:

//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", "!"};

however, I did not find a way around the constant '10'. The reason is clear though, it needs it to know how to perform accessing to the array. A possible alternative is to use #define, but I dislike that method and I #undef at the end of the header, with a comment to edit there at CPP as well in case if a change.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文