我刚读过this answer,这让我很困惑。
我一直认为类声明可以多次出现,只有定义必须只存在一次,如:
/*class Class {*/
class A; // (1) forward declaration
class A { // (2) definition, only once
int m;
};
class A; // (3) declaration again, legal?
class A a; // (4) declaration again, legal?
/*};*/
从链接的答案:(3)(和(4)?)是非法的,如果上面的代码 嵌套在类 中({{的定义和声明) 1}}嵌套在class A
)内。
在cppreference上,我找到了上述示例, 未嵌套 :
class Class
见第二行。
问题:鉴于它在类中是非法的,我的示例代码和上面的cppreference示例在不嵌套在类中时是合法的吗?或者更一般地说:类声明何时可以遵循定义(例如,如何在命名空间内)?如果它是合法的,为什么会有区别?
答案 0 :(得分:8)
来自[basic.def]:
声明(第7条)可以将一个或多个名称引入先前声明引入的翻译单元或重新声明名称。
来自[class.name]:
仅由 class-key identifier; 组成的声明是当前作用域中名称的重新声明,或者是作为类名称的标识符的前向声明。它引入了类名 进入当前范围。
所以这样做通常是合法的。 [class.mem]中只有一个例外:
成员规范中的成员不得声明两次, 除了可以声明嵌套类或成员类模板然后定义,除了可以使用 opaque-enum-declaration 引入枚举,然后使用枚举说明符重新声明
在命名空间范围内完全正常,不允许在类范围内。
至于为什么?好吧,这个规则让你“转发”声明你通常可以在任何地方所需要的所有类:
// a.h
struct C;
struct A {
C* c;
};
// b.h
struct C;
struct B {
C& c;
};
不必担心某人实际上包括完整的声明并为您打破一切:
// d.h
#include "c.h"
#include "a.h" // now C was already declared!
#include "b.h" // and here too!
struct D { ... };
这不是一个关注在类定义中的问题。它不能完全跨越多个文件。因此无法重新声明嵌套类型实际上并没有实现任何目标。
答案 1 :(得分:2)
class A;
这是不完整class A
(合法)的前瞻声明。
class A { int m; };
这是Class A
(合法)的定义。
class A;
这是class A
(合法)的重新声明。
class A a;
这是类型a
(合法)的对象A
的声明。