如何在类中初始化const成员变量?


105
#include <iostream>

using namespace std;
class T1
{
  const int t = 100;
  public:

  T1()
  {

    cout << "T1 constructor: " << t << endl;
  }
};

当我尝试t使用100 初始化const成员变量时,却给了我以下错误:

test.cpp:21: error: ISO C++ forbids initialization of member t
test.cpp:21: error: making t static

如何初始化const值?


8
使用c ++ 11,可以检查此链接stackoverflow.com/questions/13662441/…–
卡皮尔

Answers:


122

const变量指定是否变量是可修改的或没有。每次引用变量时将使用分配的常数值。在程序执行期间不能修改分配的值。

Bjarne Stroustrup的解释简要总结如下:

通常在头文件中声明类,并且通常将头文件包含在许多翻译单元中。但是,为避免复杂的链接器规则,C ++要求每个对象都有唯一的定义。如果C ++允许对需要作为对象存储在内存中的实体进行类内定义,则该规则将被打破。

一个const变量要在类中声明,但它不能在它被定义。我们需要在类外部定义const变量。

T1() : t( 100 ){}

这里的分配t = 100发生在初始化器列表中,远早于类初始化发生。


3
您能否详细说明一下Here the i = 10 assignment in initializer list happens much before the class initilizaiton occurs.我不明白的最后一个陈述。基本上,类中的这种允许定义是编译器特定的吗?
Chaitanya

3
我= 10作业?
Daniel Daranas

我的班级中有一些以上述方式初始化的常量。但是,当我尝试创建该类的对象时,operator = function not found在VC ++中出现这样的错误。可能是什么问题?
Rohit Shinde 2014年

4
当您使用某人的确切字眼而不注明出处时,这就是窃。请使用适当的归属-见stroustrup.com/bs_faq2.html#in-classstackoverflow.com/questions/13662441/...
Tanaya

是的,我也完全不理解答案中的代码-这到底是什么?可以将其放置在cpp文件实现中吗?
托马什Zato -恢复莫妮卡

50

好吧,你可以做到static

static const int t = 100;

或者您可以使用成员初始化程序:

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

2
对于他的使用(和/或意图),最好使其静止。
Mark Garcia

@FredLarson是否像某些g ++版本不允许这种初始化?还是根本不允许?
Chaitanya

3
@Chaitanya:C ++ 11非静态成员初始化器是从gcc 4.7实现的。
杰西·古德

@MarkGarcia为什么要好得多?如果const member应该从功能/对象中访问它,可能是必需的,那么为什么要静态?
Asif Mushtaq

尽管通常给静态初学者一个例子是令人误解的。因为,他们可能不知道对于该类的所有实例(对象)来说,只有一个。
Muhamed Cicak

30

有两种方法可以初始化类中的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
};

8
我认为这个答案需要澄清。为类成员使用static关键字不会添加任何使编译器满意的语法。这意味着该对象的所有实例(无论是否恒定)都有一个变量的单个副本。这是一个设计选择,需要仔细考虑。程序员可能会决定,尽管在给定对象的生存期内保持不变,但该常数类成员仍可能随不同的对象而变化。
opetrenko

同意..当我们使用static时,它将为所有对象仅创建一个副本。正如您提到的,它是一种设计选择。在所有对象都为单个副本的情况下,应该可以使用对象1和2。如果每个对象都有一个单独的副本,则可以使用3个副本
ravs2627

这个答案表明一个简单的语法更改没有后果-而将其更改为静态则不是。
艾萨克·伍兹

如果需要使用double或float-这是C ++ 11标准的一部分吗?
serup

14

如果您不想使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){}

3
我觉得这个方法比被接受的一个更好的答案....
伊恩

1
谢谢您提供清晰明了的示例,并且变体形式多个!消除了读者的歧义和额外的研究/滚动!
clearlight '18

13
  1. 您可以升级编译器以支持C ++ 11,并且您的代码可以正常运行。

  2. 在构造函数中使用初始化列表。

    T1() : t( 100 )
    {
    }

6

另一个解决方案是

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 Compiler or below则在声明时无法初始化cons成员。因此,在这里必须使构造函数初始化const数据成员。还必须使用初始化程序列表T1():t(100)立即获取内存。


0

您可以添加static以使此类成员变量的初始化成为可能。

static const int i = 100;

但是,使用内部类声明并不总是一种好的做法,因为从该类插入的所有对象将共享相同的静态变量,该静态变量存储在实例化对象的作用域内存之外的内部存储器中。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.