静态结构体与静态成员

13

今天我发现自己正在创建一个包含2个整数的静态数组,由于C++(不是C++11)不允许其内联初始化,所以我回到使用了一个类型为结构体的静态变量。

class MyWidget {
  ...
  static const struct Margin {
    const int horizontal = 1;
    const int vertical = 1;
  } margin;

};
我注意到结构体Margin的内部变量仅被用于一次,因此我决定将它们也改为静态的。

我注意到结构体Margin的内部变量仅被用于一次,因此我决定将它们也改为静态的。

class MyWidget {
  ...
  static const struct Margin {
    static const int horizontal = 1;
    static const int vertical = 1;
  } margin;

};

让我惊奇的是声明一个静态结构体变量和声明一个带有静态成员的静态结构体变量之间的区别。就我所知,静态对象只在内存中分配一次,因此无论我的成员是否为静态,Margin结构体都只会被分配一次。

我错过了什么吗?这两者之间存在差异还是只是纯粹的语法糖?


9
在C++中,没有所谓的“静态结构体”,static 是一种存储类说明符,只适用于变量或函数,而非类型。 - PlasmaHH
你不应该回到使用具有命名成员的结构体,而是使用未命名元素的数组。应该反过来。 - Karthik T
1
@Chowlett 这不太清楚。其他编程语言有静态类,OP 可能误以为 C++ 也有这个功能。 - juanchopanza
@PlasmaHH 你说得对。这就是我的意思,一个类型为struct Margin的静态常量变量。 - Pavlo Dyban
@Antonijn 我不是,所以我也搜索了静态结构,但是没有找到任何东西,决定在这里发布我的问题。正确的标题应该不是静态结构,而是类型为struct Margin的静态变量。 - Pavlo Dyban
显示剩余2条评论
3个回答

16

看起来你对“静态结构体”有些困惑,因为在C++中,并不存在所谓的静态结构体(与像C#这样的语言不同,在那里静态类是解决没有全局函数的问题的方法)。

你所做的是创建该类的一个实例,并使该实例(margin)静态(且常量)。所以你的结构体并不是静态的,你只是定义了一个结构体,并创建了一个属于MyWidgetstatic const实例。现在两个给定示例之间的区别应该是相当明显的。

在第一个示例中,你正在创建一个名为margin的静态变量,它属于MyWidget,这意味着你可以这样访问horizontal成员:

MyWidget::margin.horizontal

margin是你创建的实例。

然而,如果你将结构体的成员设为静态的,你就不能这样做。你需要像这样访问它们:

MyWidget::Margin::horizontal

Marginstruct时。然而请注意,在第二种情况下,不需要静态实例margin,因为它没有与其关联的实例字段。


那么在第二种情况下,我可以放弃 static const struct Margin {...} margin; 并简单地引用 const struct Margin {...} margin; 吗? - Pavlo Dyban
@PavloDyban 那么 margin 将成为一个实例变量,这意味着您需要一个 MyWidget 的实例才能使其工作。 - antonijn

7

确实有区别:

class MyWidget {
  ...
  static const struct Margin {
    const int horizontal = 1;
    const int vertical = 1;
  } margin;


  void foo() {
    Margin anotherMargin = { 3, 4 };
  }
};

这将创建另一个Margin实例,具有不同的成员。在“static const struct Margin {...} margin;”中,“static”适用于变量“margin”,而不是类/结构“Margin”。这意味着所有MyWidget对象共享一个Margin对象,但您可以创建其他具有不同值的Margin对象。如果horizontal和vertical本身是静态的,则上面的代码将无法编译,因为Margin对象将没有成员变量(静态不是真正的成员),因此所有Margin对象都将共享horizontal和vertical值。

3
是的,两种情况之间有显着的差异。在这两种情况下,您声明了类型为MyWidget::Margin的静态变量MyWidget::margin。在第一种情况中,margin是一个对象,具有两个字段:horizontal和vertical。在第二种情况中,margin是一个没有字段的对象,您可以直接删除该对象。
在第一种情况下,您需要使用形式margin.vertical(如果从MyWidget外部访问,则使用MyWidget::margin.vertical)来访问字段,在第二种情况下,您可以像这样使用Margin::vertical(或MyWidget::Margin::vertical)。

为什么第二个案例中的margin是一个没有字段的对象呢?静态变量不是与结构体相关联吗?在我调用Margin::vertical时,struct Margin必须知道从哪里获取水平和垂直值,对吧? - Pavlo Dyban
2
静态字段不是对象的一部分。你可以把Margin的静态字段看作是命名空间中的全局变量。 - sdkljhdf hda
就是这样!我现在明白了。因为静态变量在所有实例中都是相同的,所以我一直在考虑指针替换这些变量,但我忘记了全局变量。谢谢! - Pavlo Dyban

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