为什么一个类不能在没有前向声明的情况下具有指向另一个类的实例的指针?
Why can't a class have a pointer to an instance of another class without forward declaration?
我知道做是不可能的
class foo{
foo bar;
};
因为编译器不知道要为foo
准备多少内存。但考虑一下:
class A{
B::C* foo;
};
class B{
class C{
};
};
无论C的定义如何,编译器都会准确地知道A的大小,这似乎很合理。为什么这不可能呢?(标准明确禁止这样做吗?为了什么?)
我得到了一个非常粗略的方法来绕过约束,即将foo
视为uintptr_t
,然后将reinterpret_cast
返回到C
,这只是为了表明我真的不明白(客观)原因,我知道如果在没有正当理由的情况下使用,这是一个非常非常糟糕的做法。
最后它被证明是标准所禁止的
一个巨大的挑战如下:
class other {};
namespace N {
class foo {
other* p;
};
class other {};
}
应考虑哪个other*
?编译器工作量太大。尽管我们可以用::other
或N::other
来显式,但在上述情况下仍然会造成混淆。
TL;DR:那是因为标准规定语法是这样的。不幸的是,它就这么简单。
这是我走的路:
-
您打开标准,例如c++11草稿。
-
你要找关于课程的部分,这是第9部分。你会立即看到它有第9.2小节"集体成员"。已经定义了完整的语法。经过一段时间的阅读,你可以进入
member-declarator
。在我们的上下文中最重要的部分是declarator
。 -
第8节。声明人。在p4。您有
declarator
的语法。在浏览了所有支持的花式语法的正式定义之后,您会注意到它依赖于id-expression
。 -
5.1.1主要表达式对此进行了定义。概述(
[expr.prim.general]
)。并且它必须是unqualified-id
的qualified-id
。
所以你的问题可以改为"为什么名字查找不起作用?"但这是另一个问题。
FWIW,我想不多,但这是一个设计决定。它需要为汇编单位记录所有失败的决议。在这种情况下进行懒惰检查会带来相当深远的影响。
在示例之后
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
的同义词(如果基本原始数据指针的大小有任何变化,则指向这些类型的指针是最大的)。
然后断言:
"我上面发布的这个伪例子似乎没有什么实际意义。我之所以不想使用前向声明,是因为当您获得嵌套类时,没有可以保留封装的前向声明。
这是错误的。
例如,这很好用:
class Foo
{
private:
class Other;
Other* bar;
class Other{};
public:
Foo(): bar( new Other ) {}
};
但是,第一次使用时带有声明的快捷方式class Other* bar;
在这种情况下不起作用。这是因为它实际上会将Other
声明为命名空间级别的类,而不是嵌套类。
- 为什么我可以在不重载 "=" 运算符的情况下将一个对象分配给另一个对象?
- 如何在不复制的情况下将一个向量移动到另一个向量中
- C++在不使用pow或循环的情况下计算一个数字的幂
- 我们可以在没有新实例化的情况下声明一个抽象方法来返回抽象超类中的子类对象吗
- 在C++中,有没有一种方法可以让我在不传递参数的情况下拥有一个函数
- 是否可以在不扩展初始宏的情况下将一个宏作为参数提供给另一个宏?
- 父类有 26 个构造函数重载.如何在不复制+粘贴 26 个重载的情况下将一个小任务附加到所有构造器?
- 有什么理由在没有继承的情况下声明一个虚拟方法
- 如何在给定任意数量的整数的情况下创建一个唯一键?并使用该键存储,然后从地图中查找
- 如何在不使用数学的情况下知道一个数字是否是回文
- 如何使您的程序重复递增,直到在switch语句中按下另一个键
- 在不复制变量的情况下列出一个变量
- wxWidgets:如何在不将控制权传递给它的情况下制作一个 GUI
- 如何在<string>没有 std::string 中介的情况下制作一个支持通过 C 字符串查找的集合?
- 有没有办法在不知道它的大小的情况下制作一个字符数组
- 我想在不使用字符串的情况下声明一个指向字符的指针数组
- 如何在不把内部类的定义放入父类的情况下创建一个内部类
- Boost::在gcc4.6不工作的情况下分配一个大映射的静态初始化
- 我怎样才能在不出错的情况下保存一个unsigned long
- 如何在不使用平方根的情况下检查一个整数是否是完全平方数