我知道一个班级不能拥有同一班级的成员,例如
class Sample {
int a = 0;
Sample s; // error, object would need infinite size
};
但是如何拥有一个指针是好的?
class Sample {
// this compiles, but isn't it essentially the same
// as above?
Sample() { s = new Sample(); }
int a = 0;
Sample *s;
};
答案 0 :(得分:1)
允许指针作为成员,因为指针具有固定大小(32位应用程序中为4个字节,64位应用程序中为8个字节),因此编译器可以在编译时知道Sample
的完整大小,它不依赖于指针在运行时指向的内容。
在Sample
构造函数中创建Sample
的实例不是语法错误,因此编译器允许它,但它会在运行时导致无限递归循环。所以不要这样做。
答案 1 :(得分:1)
一般来说,编译器擅长检测类型的问题,而不善于检测值的问题。
在后一种情况下,有时那是因为它不能(它怎么能知道十年后发生的事情?),有时它是因为它不能真正被打扰(读:标准不需要它做数学上困难的事情,因为那将是一种意思)。
在第一个示例中,递归定义是类型显示的问题。编译器总是知道你已经完成了它。事实上,它没有办法创建一个与源代码匹配的程序:没有这样的东西可以在数学上存在 - 它会永远存在。
但运行时间接开辟了新的机会!指针不 指向任何东西。您可以将s
保持未初始化状态,或将其初始化为nullptr
,这样就可以了。您可以通过if
电话将选项保留为rand()
。编译器可以做的最好的事情是分析构造函数体,看看你是否递归实例化Sample
。但最终,这比编译器或标准更愿意放入 1 ,所以它就成了你的问题。
简而言之:就是它的方式。
1。如果你的构造函数体在另一个翻译单元中怎么办?这次不是,但C ++喜欢一般规则......
答案 2 :(得分:0)
class Sample {
int a = 0;
Sample s; // error, object would need infinite size
};
Sample
的定义在你声明Sample s;
的地方未完成,因此编译器不知道应该分配多少大小......它不知道是什么sizeof(Sample)
。
指向自身的指针,即Sample *s;
,是标准大小,具体取决于您编译代码的目标平台。