如何初始化一个常量数据成员?

150
#include <iostream>

using namespace std;
class T1
{
  const int t = 100;
  public:
  
  T1()
  {
    cout << "T1 constructor: " << t << endl;
  }
};

当我尝试用100来初始化常量数据成员t时,却出现了以下错误:
test.cpp:21: error: ISO C++ forbids initialization of member ‘t’
test.cpp:21: error: making ‘t’ static

如何初始化一个`const`成员?

15
使用C++11可以实现这一点,可以查看以下链接:https://dev59.com/pWYr5IYBdhLWcg3wdp4C - PapaDiHatti
c++11支持在成员声明中包含花括号或等于号初始化器。 - Cauchy Schwarz
12个回答

155
const变量指定变量是否可以修改。每次引用该变量时,都将使用分配的常量值。在程序执行期间,无法修改分配的值。
Bjarne Stroustrup的解释简要概括了这一点:
类通常在头文件中声明,头文件通常包含在许多翻译单元中。但是,为了避免复杂的链接器规则,C++要求每个对象具有唯一的定义。如果C++允许需要作为对象存储在内存中的实体的内部类定义,则会违反该规则。 const变量必须在类内声明,但不能在其中定义。我们需要在类外定义const变量。
T1() : t( 100 ){}

这里的赋值t = 100发生在初始化列表中,在类初始化之前就完成了。


6
您能否对最后一句话“这里在初始化列表中的 i = 10 赋值发生在类初始化之前”的表述再详细说明一下?我不太理解。此外,允许在类内定义变量的实现方式基本上是由编译器决定的,是吗?回答:可以。这句话的意思是,在使用初始化列表进行类初始化时,i = 10 的赋值操作会在类初始化之前执行。至于在类内定义变量的实现方式,基本上取决于编译器。 - Chaitanya
5
如果您未注明来源就抄袭了他人的原话,那么这被称为剽窃。请使用适当的引用——参见http://www.stroustrup.com/bs_faq2.html#in-class 和https://dev59.com/pWYr5IYBdhLWcg3wdp4C。 - Tanaya
是的,我也完全不理解答案中的代码 - 那是什么鬼?它可以放在cpp文件实现中吗? - Tomáš Zato
我会使用不同的措辞:“const 指定变量是否只读”或“const 指定变量是否可被代码修改”。想想“const volatile int myVar”,它指定你可以从 myVar 读取,但 myVar 可能会改变。 - Sil
这是一个很好的解释,但在我看来,它与堆栈中函数的使用方式不太一致。内存就是内存,操作就是操作。在我看来,这相当古怪,并导致开发人员不考虑数据结构进行有意义的工作。造成了损失。 - Kalen
显示剩余3条评论

65

好的,你可以将其设为静态

static const int t = 100;

或者你可以使用成员初始化器:

T1() : t(100)
{
    // Other constructor stuff here
}

2
对于他的使用(和/或意图),将其设置为静态会更好。 - Mark Garcia
@FredLarson 这是不是意味着某些 g++ 版本不允许这种初始化方式?还是根本就不允许使用这种方式? - Chaitanya
3
C++11的非静态成员初始化器从gcc 4.7开始实现。 - Jesse Good
1
通常给初学者静态的例子是误导性的,因为他们可能不知道它只适用于该类别的所有实例(对象)中的一个。 - Silidrone
如果它是“const”,有什么区别吗? - Fred Larson
显示剩余2条评论

44

有几种方法可以在类内部初始化const成员变量。

通常const成员的定义需要对变量进行初始化。

1) 如果您想在类内初始化const,语法如下:

static const int a = 10; //at declaration

2) 第二种方法可以是

class A
{
  static const int a; //declaration
};

const int A::a = 10; //defining the static member outside the class

3)如果您不想在声明时初始化变量,那么另一种方式是通过构造函数,在初始化列表中初始化变量(而不是在构造函数体中)。它必须像这样:

class A
{
  const int b;
  A(int c) : b(c) {} //const member initialized in initialization list
};

18
我认为这个答案需要澄清。在类成员中使用静态关键字不是为了添加一些任意的语法以使编译器满意,而是表示该变量对于对象的所有实例都只有一个副本,无论是否为常量。这是一个需要仔细考虑的设计选择。在后续开发中,程序员可能会决定即使在给定对象的生命周期内保持不变,此常量类成员仍可因不同对象而异。 - opetrenko
同意。当我们使用静态时,它为所有对象创建一个副本。正如您所提到的,这是一种设计选择。 如果所有对象只有一个副本,则1和2应该可以工作。 如果每个对象都有单独的副本,则3会起作用。 - ravs2627
这个答案建议进行一个简单的语法更改,没有任何后果 - 而将其更改为静态则不是。 - Isaac Woods
如果您需要使用double或float,这是否是C++11标准的一部分? - serup

24

如果你不想把类中的const数据成员设置为静态,那么你可以使用类的构造函数来初始化const数据成员。

例如:

class Example{
      const int x;
    public:
      Example(int n);
};

Example::Example(int n):x(n){
}

如果类中有多个const数据成员,您可以使用以下语法来初始化这些成员:

Example::Example(int n, int z):x(n),someOtherConstVariable(z){}

5
我认为这个回答比被采纳的那个更好。 - Ian
2
感谢您提供清晰明了的示例,以及展示复数形式的变体!这消除了读者在阅读过程中的歧义和额外的研究/滚动! - clearlight

14
  1. You can upgrade your compiler to support C++11 and your code would work perfectly.

  2. Use initialization list in constructor.

    T1() : t( 100 )
    {
    }
    

9
另一种解决方案是:
class T1
{
    enum
    {
        t = 100
    };

    public:
    T1();
};

所以 t 被初始化为 100,它不能被更改,并且它是私有的。


3

如果成员是数组,则比普通情况稍微复杂一些:

class C
{
    static const int ARRAY[10];
 public:
    C() {}
};
const unsigned int C::ARRAY[10] = {0,1,2,3,4,5,6,7,8,9};

或者

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

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

2

另一种可能的方式是命名空间:

#include <iostream>

namespace mySpace {
   static const int T = 100; 
}

using namespace std;

class T1
{
   public:
   T1()
   {
       cout << "T1 constructor: " << mySpace::T << endl;
   }
};

缺点在于,如果其他类包含头文件,它们也可以使用这些常量。

1

这是正确的做法。你可以尝试这段代码。

#include <iostream>

using namespace std;

class T1 {
    const int t;

    public:
        T1():t(100) {
            cout << "T1 constructor: " << t << endl;
        }
};

int main() {
    T1 obj;
    return 0;
}

如果您使用的是C++10编译器或更低版本,则无法在声明时初始化const成员。因此,必须编写构造函数来初始化const数据成员。还必须使用初始化列表T1():t(100)来立即获取内存。

1
在C++中,您不能在声明时直接初始化任何变量。为此,我们必须使用构造函数的概念。
看这个例子:
#include <iostream>

using namespace std;

class A
{
    public:
  const int x;  
  
  A():x(0) //initializing the value of x to 0
  {
      //constructor
  }
};

int main()
{
    A a; //creating object
   cout << "Value of x:- " <<a.x<<endl; 
   
   return 0;
}

希望能对你有所帮助!请点赞支持。

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