6

主题已在此处(在哪里声明/定义 C++ 中的类范围常量?),特别是在此处得到解决。

在积分常数的情况下,我想完全理解的是:

//In the header
class A {
private:
static const int member = 0; //Declaration and definition
};

和:

//In the header
class A {
private:
static const int member; //Only declaration
};

//In the cpp
const int A::member = 0; //Definition

(我知道第二个可能的好处是,如果我更改常量的值,我只需要重新编译一个文件)

附带问题:
例如,在访问的标头中定义的内联方法会发生什么member?它会不会被内联?如果走到一个极端,所有方法都在头文件中定义为内联方法并且所有常量都在 cpp 文件中定义,会发生什么?

编辑:

我的道歉:我认为没有必要,但我错过了成员是静态的这一事实。我的问题仍然存在,但现在代码是合法的。

4

3 回答 3

6

如果在将问题更改为静态之前,它是一个非静态成员,那么它只能在构造函数的初始化列表或(自 2011 年以来)成员的声明中初始化。你的第二个例子格式不正确。

如果它是静态的,那么如果它是odr-used则需要一个定义:粗略地说,如果你做任何需要它的地址而不仅仅是它的值的事情。如果您只使用该值,那么第一个示例就可以了。但请注意,评论是错误的——它只是一个声明,而不是一个定义。

如果您确实需要定义,那么由您决定是在声明中指定值还是在定义中指定值。在声明中指定它允许更好的优化范围,因为在使用变量时该值始终可用。在定义中指定它可以提供更好的封装,如果一个翻译单元发生变化,只需要重新编译它。

例如,在访问成员的标头中定义的内联方法会发生什么?它会不会被内联?

访问在另一个翻译单元中定义的数据对象没有理由阻止函数被内联。

于 2013-08-09T07:22:59.930 回答
2

有两个观点需要考虑,即可见性和寻址。

请注意,两者是正交的,因为您实际上可以将变量声明为已初始化,并且仍然在翻译单元中定义它,因此它在内存中具有有效地址。

能见度

可见性影响变量的使用,并具有一些技术影响。

为了在模板代码中用作非类型模板参数,该值必须在使用时可见。此外,在 C++11 中,这可能是constexpr使用所必需的。否则,该值不必可见。

从技术上讲,可见值可以触发编译器的优化。例如if (A::member)是微不足道的错误,因此可以省略测试。这通常被称为常量传播。虽然这似乎是一件好事,但乍一看,却产生了深远的影响:头文件的所有客户端都可能依赖于该值,因此对该值的任何更改都意味着应该重新编译它们。如果将此标头作为共享库的一部分提供,这意味着更改此值会破坏 ABI。

寻址

这里的规则很简单:如果变量可以被寻址(通过指针或引用传递),那么它需要驻留在内存中的某个地方。这需要在一个翻译单元中进行定义。

于 2013-08-09T08:56:49.200 回答
2

这就是数据隐藏的问题。是否要公开内部类字段。如果您正在发布一个类库并希望隐藏实现细节,那么最好在界面中显示尽可能少的实体,那么即使声明私有字段member也太多了。

我只是将这个值声明为.cpp文件中的静态变量。

于 2013-08-09T07:00:33.320 回答