如何在头文件中声明静态const char*?

Mar*_*ark 57 c++ constants

我想在头文件中为我的.cpp文件定义一个常量char*.所以我试过这个:

private:
    static const char *SOMETHING = "sommething";
Run Code Online (Sandbox Code Playgroud)

这给我带来了以下编译器错误:

错误C2864:'SomeClass :: SOMETHING':只能在类中初始化静态const积分数据成员

我是C++的新手.这里发生了什么?为什么这是非法的?你怎么能这样做呢?

Kea*_*eks 66

您需要在翻译单元中定义静态变量,除非它们是整数类型.

在你的标题中:

private:
    static const char *SOMETHING;
    static const int MyInt = 8; // would be ok
Run Code Online (Sandbox Code Playgroud)

在.cpp文件中:

const char *YourClass::SOMETHING = "something";
Run Code Online (Sandbox Code Playgroud)

C++标准,9.4.2/4:

如果静态数据成员是const integer或const枚举类型,则它在类定义中的声明可以指定一个常量初始化器,它应该是一个整型常量表达式.在这种情况下,成员可以在其范围内出现在整数常量表达式中.如果在程序中使用该成员,并且名称空间范围定义不包含初始化程序,则该成员仍应在名称空间作用域中定义.

  • 因为指针不是整数类型.积分仅包含内置插件. (3认同)
  • `DWORD`是Windows SDK中定义的众多typedef之一.它转换为`unsigned int`,这是一个整数类型. (2认同)

AnT*_*AnT 27

回答OP的问题,为什么只允许使用整数类型.

当一个对象被用作左值(即作为存储中具有地址的东西)时,它必须满足"一个定义规则"(ODR),即它必须在一个且仅一个翻译单元中定义.编译器不能也不会决定在哪个转换单元中定义该对象.这是您的责任.通过在某个地方定义该对象,您不仅仅是定义它,您实际上是在这个特定的翻译单元中告诉编译器您要在此处定义它.

同时,在C++语言中,积分常量具有特殊的地位.它们可以形成整数常量表达式(ICE).在ICE中,积分常数用作普通,而不是对象(即,这种积分值是否在存储器中具有地址并不相关).实际上,ICE在编译时进行评估.为了促进这种积分常数的使用,它们的值必须在全局范围内可见.常量本身并不需要存储中的实际位置.由于这个积分常数得到了特殊的处理:它被允许在头文件中包含它们的初始化器,并且放宽了提供定义的要求(首先事实上,然后是法律上的).

其他常量类型没有这样的属性.其他常量类型实际上总是用作左值(或者至少不能参与ICE或类似于ICE的任何东西),这意味着它们需要定义.其余的如下.

  • @Mooing Duck:ODR的全文相当广泛.它有很多"例外"和"非例外",它们甚至不限于"模板".我的答案仅限于处理积分常数的ODR的一个小的相关部分.我不明白你的"模板除外"评论在这里是如何相关的(我甚至不明白你的意思究竟是什么意思.) (2认同)
  • 这一切都是真的,我给了+1,因为这是一个很好的答案,但模板类(据我所知)是所有ODR规则的例外.我以为我会把它丢在那里. (2认同)

Ign*_*tor 18

使用C++ 11,您可以使用constexpr关键字并在标题中写入:

private:
    static constexpr const char* SOMETHING = "something";
Run Code Online (Sandbox Code Playgroud)


笔记:


Ste*_*sop 17

错误是您无法static const char*在类中初始化.您只能在那里初始化整数变量.

您需要在类中声明成员变量,然后在类外部初始化它:

//头文件

class Foo {
    static const char *SOMETHING;
    // rest of class
};
Run Code Online (Sandbox Code Playgroud)

// cpp文件

const char *Foo::SOMETHING = "sommething";
Run Code Online (Sandbox Code Playgroud)

如果这看起来很烦人,可以认为它是因为初始化只能出现在一个翻译单元中.如果它在类定义中,那通常会包含在多个文件中.常量整数是一种特殊情况(这意味着错误消息可能不像它可能那样清晰),并且编译器可以有效地将变量的使用替换为整数值.

相反,char*变量指向内存中的实际对象,这是实际存在所必需的,并且它是使对象存在的定义(包括初始化)."一个定义规则"意味着您因此不希望将其放在标题中,因为包含该标题的所有翻译单元都将包含该定义.它们无法链接在一起,即使字符串在两者中都包含相同的字符,因为在当前的C++规则下,您已经定义了两个具有相同名称的不同对象,这是不合法的.他们恰好在其中具有相同的字符这一事实并不能使其合法化.


pga*_*ast 9

class A{
public:
   static const char* SOMETHING() { return "something"; }
};
Run Code Online (Sandbox Code Playgroud)

我一直这样做 - 特别是对于昂贵的const默认参数.

class A{
   static
   const expensive_to_construct&
   default_expensive_to_construct(){
      static const expensive_to_construct xp2c(whatever is needed);
      return xp2c;
   }
};
Run Code Online (Sandbox Code Playgroud)