C++数组常量成员(初始化)

19

我有一个包含数组的类。我想让这个数组的长度设置为一个常量:

// Entities.h
    class Entities
    {
        private:
            const int maxLimit;
            int objects[maxLimit];
            int currentUsage;

        public:
            Entities();

            bool addObject(int identifier);
            void showStructure();
    };

我遇到的主要问题在于构造函数。我的想法是:

// Entities.cpp
    Entities::Entities() : maxLimit(50)
    {
        currentUsage = 0;
        cout << "Entities constructed with max of 50" << endl;
    }

本来可以足够......但并非如此。我不知道是否可以使用初始化列表进行数组初始化。

我该如何使用 maxLimit 常量来初始化 objects 数组?虽然我有 Java 的经验,但对 C++ 中的类相对较新。我主要是在测试 'constness' 现象。


2
小心!你很快就会成为一个常量成瘾者! - xtofl
6个回答

37

数组必须具有一个固定的长度。我的意思是,对于该类别的所有对象,它们的长度都必须相同。这是因为编译器必须知道每个对象的大小,并且对于该特定类别的所有对象,它们的大小必须相同。所以,以下代码可以实现:

class Entities
{
    private:
            static const int maxLimit = 50;
            int objects[maxLimit];
            int currentUsage;

    public:
            Entities();

            bool addObject(int identifier);
            void showStructure();
};

然后在 cpp 文件中:

const int Entities::maxLimit;

我更喜欢使用枚举来实现这个,因为这样我就不需要在cpp文件中定义静态变量了:

class Entities
{
    private:
            enum { maxLimit = 50 };
            int objects[maxLimit];
            int currentUsage;

    public:
            Entities();

            bool addObject(int identifier);
            void showStructure();
};

如果你想要一个每个对象都有大小的数组,那么你可以使用动态数组。 vector就是这样一个数组:

class Entities
{
    private:
            const int maxLimit;
            std::vector<int> objects;
            int currentUsage;

    public:
            Entities();

            bool addObject(int identifier);
            void showStructure();
};

// Entities.cpp
Entities::Entities(int limit) 
    : maxLimit(limit), objects(limit), currentUsage(0)
{
    cout << "Entities constructed with max of 50" << endl;
}

最好尽可能在初始化列表中完成尽可能多的初始化工作。


5
+1 对于枚举提示,通常是绕过静态整数的最佳“技巧”。 - Robert Gould
2
+1 这种解决方案不使用动态内存,这意味着它比迄今为止提出的任何其他建议更好(就回答他问题的精神而言)。 - Brian
顺便提一下,如果您正在使用向量,则私有的maxLimit成员将是多余的。 - Brian
Brian,如果向量的大小在运行时指定,那么它分配的内存实际上会来自堆吗?或者说向量是否足够聪明,可以在堆栈上自我扩展? - Joseph Garvin
2
Joseph,向量解决方案从堆中获取内存。前两个分配不需要堆。C++1x将具有std::dynarray,用于确定运行时长度,但仍具有恒定长度(即不改变长度),并在可能的情况下从堆栈中分配。 - Johannes Schaub - litb
显示剩余2条评论

11

如果您需要在编译时设置数组大小,则可以使用模板参数:

template<size_t maxLimit>
class Entities
{
    int objects[maxLimit];
    public:
        Entities() {}
        ...
};

Entities<1000> inst;

但这意味着将类体对所有客户端可见。 - xtofl
嗯,类体始终对所有客户端可见,你的意思是什么? - Iraimbilanja

1

为了动态分配内存,您可能需要使用'new'关键字,例如

对象的定义方式如下:

int * objects;

在构造函数内部,您可以这样做:

objects = new int [maxLimit];

编辑:

忘了提到,当完成操作后,你需要解除数组的分配,可能需要在类的析构函数中实现。

delete[] objects;

最好包括一个复制构造函数和operator=(),否则意外的复制将导致析构函数被调用两次。(例如,在同一指针上两次使用delete[]) (或者你可以使类不可复制。) - Mr.Ree
最好使用std::vector<int>对象; 对象.resize(maxLimit);,这样可以避免赋值运算符和析构函数的问题。 - Johann Gerell

0

const int必须在声明时初始化。如果你不知道在声明时应设定的值,那么你将需要采用不同的策略。

你将需要在构造函数中创建数组,并保留一个指针。这是你想做的吗?

在你的类中:

private:
    int maxLimit;
    int* objects;

而在外面:

Entities::Entities() : maxLimit(50)
{
    currentUsage = 0;
    cout << "Entities constructed with max of 50" << endl;
    objects = new int[maxLimit];
}

Entities::~Entities()
{
    delete [] objects;
}

你可以在构造函数的初始化列表中初始化const int。在你的例子中,maxLimit可以是const。你忘记了复制构造函数和operator=()。意外复制这个对象将导致析构函数运行两次。(两次删除相同的指针delete[]。) - Mr.Ree
顺便提一下,你不能在声明点初始化它们(但静态常量可以初始化)。 - MSalters

0
如果所有对象长度相同,则长度可以是静态的。这使它成为一个常量整数表达式,允许作为数组边界:
class Entities
{
    private:
        static const int maxLimit = 50;
        int objects[maxLimit];
        int currentUsage;
    //...
};

请注意,sizeof(Entities)是一个有效的表达式。每个Entities对象都具有相同的大小。

0
使用std::vector,您将获得预期的行为。无需担心指针、副本等问题。
#include <vector>

class Entities
{
private:
  const int limit;
  std::vector<int> objects;

public:
  Entities(int a_limit)
    : limit(a_limit), objects(a_limit)
  { }

  void addObject(int identifier)
  {
    if (objects.size() == limit)
      throw whatever;
    objects.push_back(identifier);
  }
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接