我知道这是不可能的
class foo{
foo bar;
};
因为编译器不知道为foo
准备多少内存。
但请考虑:
class A{
B::C* foo;
};
class B{
class C{
};
};
无论C的定义如何,编译器都能确切地知道A的大小似乎是合理的。为什么这不可能呢? (标准是否明确禁止?为什么?)
我有一个非常粗略的方法绕过将foo
视为uintptr_t
的约束,然后reinterpret_cast
将其视为C
,这只是为了表明我真的没有得到(客观)理由,而且我知道如果没有正当理由的话,这是非常糟糕的做法。
最后,标准禁止这样做。
答案 0 :(得分:1)
一个重大挑战是:
class other {};
namespace N {
class foo {
other* p;
};
class other {};
}
应该考虑哪个other*
?编译器的工作量太大了。虽然我们可以通过::other
或N::other
明确表达,但在上述情况下仍会造成混淆。
答案 1 :(得分:0)
TL; DR:那是因为标准规定语法是这样的。不幸的是,它就像那样简单。
这是我遵循的路径:
您打开标准,例如c++11 draft
您在第9节中寻找关于课程的部分。您立即看到它有“9.2级成员”小节。定义了完整的语法。经过一些阅读后,您将进入member-declarator
。我们背景中最重要的部分是declarator
。
第8节。声明者。在第4页。你有declarator
的语法。在完成所支持的花哨语法的所有正式定义后,您会注意到它取决于id-expression
。
这在5.1.1主表达式中定义。一般([expr.prim.general]
)。它必须是qualified-id
的{{1}}。
因此,您的问题可以改为“为什么名称查找不起作用?”但这是另一个问题。
FWIW,我猜不多,但这是一个设计决定。它需要跟踪编译单元的所有失败的分辨率。在这种情况下进行懒惰检查具有非常深远的影响。
答案 2 :(得分:0)
示例后
class foo{
other* bar;
...
};
class other{
...
}
...其中(1)使用未声明的名称,(2)缺少关键的分号,你问
“为什么这不可能呢? (标准是否明确禁止?为什么?)
圣标要求每个名字必须在使用前声明。
请注意,在给定的C ++实现中,即使数据指针也可以具有不同的大小(void*
保证能够保存任何数据指针),更不用说函数指针了。
声明在首次使用前声明的替代方法可能是采用默认值,例如在早期C天使用隐式int
。例如。编译器可以假设other
是类类型。但这在一般情况下并不是很有用,而且会使语言复杂化。
但是,在这种特殊情况下,可以将other
的必要最小声明与其首次使用结合起来:
class foo{
class other* bar;
//...
};
class other{
//...
};
或者您可以使用普通的前向声明:
class other;
class foo{
other* bar;
//...
};
class other{
//...
};
正因为编译器知道other
是类类型,而不是例如一个函数,或char
或void
的同义词(如果基本原始数据指针的大小有任何变化,则指向这些类型的指针是最大的。)
然后断言:
“上面发布的虚拟示例似乎没有任何实际意义。我没有前向声明的原因是,当你有一个嵌套类时,没有可以保留封装的前向声明。
那是错的。
E.g。这很好用:
class Foo
{
private:
class Other;
Other* bar;
class Other{};
public:
Foo(): bar( new Other ) {}
};
但是,在第一次使用中使用声明的快捷方式class Other* bar;
在这种情况下不起作用。那是因为它有效地将Other
声明为命名空间级别类而不是嵌套级别。