类声明大括号后要加分号

97
在C++类中,为什么在右括号后要加分号?我经常忘记它,导致编译器错误,浪费时间。对我来说似乎有些多余,但这不太可能是情况。人们真的会这样做吗:
在C++中,分号用于标记语句的结尾。类定义被视为一个声明,并且必须以分号结尾,就像其他声明一样。因此,在类定义的最后一个右括号后面需要加上分号。
class MyClass
{
.
.
.
} MyInstance;

我理解为结构体和枚举类型是考虑了C语言的兼容性,但由于类不是C语言的一部分,我猜这主要是为了保持相似声明结构之间的一致性。

我所寻求的更多与设计原理有关,而不是能否改变任何内容,尽管一个好的代码补全IDE可能会在编译之前捕捉到这个问题。


4
这可能有所帮助:http://www.cpptalk.net/confused-about-the-meaning-of-the-semicolon-vt11965.html - Michael Haren
1
@Michael,感谢提供链接。从历史的角度来看,这是有道理的。如果C++允许所有的C语法,并且C++类与结构体同义,那么我们就必须在类的末尾加上必要的分号。 - SmacL
3
@Brian,没错,这是一个严肃的问题。我很清楚我不得不接受它,但我很好奇设计和实现背后的理念。 - SmacL
类本质上就是结构体,唯一的区别在于它们的默认访问级别(私有 vs 公共)。因此,关于分号的使用没有任何区别。我想这就是为什么我如此难以置信的原因。 :) - Brian Neal
@BrianNeal,这个问题现在已经很老了,但我认为类与结构体的根本区别在于它们还可以包含函数。我的意思是,是的,它们与结构体非常相似,但默认访问级别并不是唯一的区别,而封装函数的能力使它们非常不同。所有这些只是想说我觉得注明它们之间的某些差异是有道理的。 - Ryan Blanchard
显示剩余4条评论
8个回答

91

提供的链接似乎提供了根本原因。正如其他人指出的那样,分号是从C语言继承而来的。但这并不能解释为什么C语言首先使用它。讨论包括了这个例子:

struct fred { int x; long y; }; 
main() 
{ 
  return 0; 
} 

旧版本的 C 语言在函数没有声明返回值类型时默认返回 int 类型。如果我们在结构体定义末尾省略 ;,不仅会定义一个名为 fred 的新类型,还会声明 main() 函数将返回一个 fred 实例。也就是说代码将被解析为:

struct fred { int x; long y; } main()
{ 
  return 0; /* invalid return type, expected fred type */
} 

2
是的,隐式的 int 返回类型会在这里引发一些问题。不错的代码块。 - Gaspa79

57

在类型声明的右花括号之后必须加上分号,这是语言要求的。自 C 语言最早期版本以来就是这样。

是的,人们确实会使用你刚刚展示的声明方式。这对于在方法内创建作用域类型非常有用。

void Example() {
  struct { int x; } s1;
  s1.x = 42;

  struct ADifferentType { int x; };
}
在这种情况下,我认为为什么需要分号是很明显的。至于在头文件中声明时为什么需要它,我不确定。我的猜测是这是历史遗留问题,是为了使编写编译器更容易而采取的措施。

为什么我不能只创建作用域类型而不指定MyInstance?这似乎很奇怪,因为你结合了两个操作:声明新类型和声明新变量。 - Mykola Golubyev
@Mykola 你两个都可以做。看看我添加的示例。 - JaredPar
这是为了使编写编译器更容易而完成的。例如,尾随返回类型。为什么我们需要尾随返回类型?因为C++编译器太愚蠢了,无法解析模板定义的下一个30个字符,以找出decltype(T)的T是否存在。然后我们不能使用尾随返回类型,因为编译器又太愚蠢了,所以我们需要在方法前面键入auto,以便编译器知道它需要等待后面的内容。这种“程序员可以使编译更容易”的哲学让我对C++感到非常不满。 - Thomas Weller

17

我猜这是因为类是声明,即使它们需要花括号进行分组。而且,历史上的论点是,由于在C语言中可以这样做:

struct
{
  float x;
  float y;
} point;

在 C++ 中,你应该能够做类似的事情,在 class 声明中表现出相同的行为是有意义的。


11

它是缩写,意思是

class MyClass
{
.
.
.
};

// instance declaration
MyClass MyInstance;  // semicolon here
类声明后花括号后面的分号实际上是多余的,但这是C ++定义的方式。变量声明后的分号始终是必需的并且有意义。

1
那么,C++在每个声明后需要分号吗? - Loai Abdelhalim
1
请注意,这种方式不能创建匿名类的对象,而另一种方式可以。 - Kevin

5

我不使用这样的声明。

class MyClass
{
.
.
.
} MyInstance;

但在这种情况下,我可以理解为什么要加分号。
因为它就像int a; - 变量声明一样。

可能是为了保持一致性,因为您可以省略'MyInstance',所以分号还在那里。


2

由于兼容性原因,在 struct 后需要使用它,你希望这样做:

struct MyStruct { ... };
class  MyClass  { ... }    //inconsistency

3
但是namespace myNamespace { ... } // 不一致但有效怎么办? - Chris K

2
在C/C++中,分号(;)是语句终止符。所有的语句都以分号结束,以避免歧义(并简化解析)。语法在这方面是一致的。即使类声明(或任何块)有多行,并用{}界定,它仍然只是一个语句({}是语句的一部分),因此需要用分号结束(分号不是分隔符/定界符)。
在你的例子中,
class MyClass{...} MyInstance;

这是完整的语句。 在一条语句中可以定义多个声明类的实例。

class MyClass{...} MyInstance1, MyInstance2;

这完全符合在单个语句中声明多个基本类型实例的要求:
int a, b, c;

为什么很少看到这样的类和实例声明,因为实例只能是全局变量,除非它们是静态和/或 Plain Old Data(简单的旧数据)结构,否则你通常不需要全局对象。


4
函数定义也是一种语句,但不需要分号。 - JP Zhang

0
我们可以定义一个 class something {...}accum, trans;,其中 accum 和 trans 可以是该类的两个对象。因此,要声明该类的对象,我们在类后面使用 分号

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