“只能在类中初始化静态常量整数变量”

Posted

技术标签:

【中文标题】“只能在类中初始化静态常量整数变量”【英文标题】:"Only static constant integral variables may be initialized within a class " 【发布时间】:2015-05-10 07:35:02 【问题描述】:

有人可以向我解释为什么我不能在类中初始化一个静态变量吗?编译时到底发生了什么?

例如:

class Object 
    static int numberOfObjects = 0; // This gives the error
    Object() 
        nummberOfObjects++;
    
;

谢谢!

【问题讨论】:

请注意,这只适用于 C++11 之前的版本。 请发布发出此警告的代码。 【参考方案1】:

这只是编译器实现的标准中的一条规则。这是一条规则这一事实并不意味着相反是不可能的,正如新的 C++11 标准和相应编译器的变化所显示的那样。

【讨论】:

【参考方案2】:

在 C++11 之前的 C++ 版本中,语言标准根本不允许您在类声明中执行静态变量定义。换句话说,你不能初始化它,因为它不是常量。由于它可以在执行期间发生变化,编译器需要在某处分配一些内存来实际保存值。由于这是一个类声明,它实际上并没有为您分配内存。 const 值不存在此问题,因为它们不需要分配内存——它们实际上是“硬编码”的,就像用文字(或旧的“C”样式#define)替换它们一样。

你需要在类声明之外有一行代码,基本上说:

    int Object::numberOfObjects = 0;

这一行不只是初始化静态类变量,它实际上分配了一个静态 int 用于存储值。类声明中的代码行并没有这样做——它只是告诉编译器这样的值存在于某处。

请注意,从 C++11 开始,此行为有所不同。该语言现在足够智能,可以确定您确实想要定义的内存,因此您不再需要手动执行此操作。

【讨论】:

这个解释有很多缺陷。首先,这不是真的,因为您尝试使用的功能可以与较新的 C++ 版本一起使用。其次,这种解释很糟糕,因为inline 函数可以被声明多次(前提是它们遵守 ODR)并且链接器会抛出除其中一个之外的所有函数。此外,如果您将 std::string x = "abc"; 放在标头中,它将为此分配内存(但如果多次包含它会违反 ODR,除非使用 staticconst)。 这些都是好点。编译器执行初始化在理论上当然不是不可能的;相反,编译器在 C++11 之前根本没有以这种方式运行。我试图提供一个直观的推理来解释为什么编译器会以这种方式运行——我并不是要暗示它不能以任何其他方式运行。谢谢指正! 我不确定我是否理解你关于内联函数的观点。这些与变量定义并不完全相同,因为您没有保留要写入的内存。使用内联,你确实允许编译器做更多的剪切和粘贴——再次;它们非常类似于旧的 C 预处理器宏可能会做的事情。 您可以在头文件中包含该定义的事实是正确的,但完全无关紧要。那行代码恰好位于头文件中,但它本身不是类声明的一部分。无论是在“.c”文件中还是包含在“.h”中都是纯粹的约定,它对编译器没有任何影响——事实上,编译器只看到该行已添加到源代码中的后预处理输入通过#include 语句。 const 值可能需要分配内存,例如,如果您获取它们的地址。 (这方面的技术术语是odr-used)。所以你的理由是不正确的。无论如何,您的帖子最好将语言规则与您添加的理由明确区分开来。

以上是关于“只能在类中初始化静态常量整数变量”的主要内容,如果未能解决你的问题,请参考以下文章

直接初始化&拷贝初始化&值初始化

Java的初始化块

Kotlin类的初始化 ④ ( lateinit 延迟初始化 | ::属性名称.isInitialized 检查属性是否初始化 | lazy 惰性初始化 )

Kotlin类的初始化 ④ ( lateinit 延迟初始化 | ::属性名称.isInitialized 检查属性是否初始化 | lazy 惰性初始化 )

零初始化、静态初始化和值初始化有何不同?

类初始化与实例初始化