现在了一段时间,我一直在试图环绕为什么一些吃人类可以编译原因,我的头。
在我继续下去,也许我应该解释一下我所说的吃人的类。不知道如果我只是发明了这个词,或者如果它已经存在了一段时间,甚至如果我正确地使用它,但是这并不重要,现在。
我基本上调用一个食人族类,消费本身就是一个类。换句话说类的接口声明了自己的类型的成员。例如:
类Foo
{
公共富SomeFoo;
}
正如你可以在上面看到,类Foo有一个类型的成员美孚(本身)。
现在,我第一次看到这个(looong时间前)我没有的东西它要编译,但它让我吃惊它编译。为什么我没有事情的原因,这将汇编是因为我这个尖叫某些类型的递归恶梦。
要稍微更复杂的是,我决定尝试同样的事情,但使类结构,例如:
结构美孚
{
公共富SomeFoo;
}
不幸的是,这并不能编译,而不是你的错误: 结构成员类型'富'的'Foo.SomeFoo引起的结构布局的
在我看来,一个编译错误,使更多的意义上,没有错误,但我相信有大部分是一个合乎逻辑的解释这种行为,所以我在想,如果你们的任何人都可以解释这种现象。
感谢。
解决方案您不能设计一个结构类似,这是因为结构时,会分配一些默认值进行初始化的原因。所以,当你有一个struct 富
像你描述的,你创建一个富
...
富X; // X =默认(美孚)
它调用的默认构造函数富
。然而,默认的构造函数已经给了 Foo.SomeFoo
字段的默认值。
嗯,怎么就找不到呢?它叫默认(美孚)
。其中,以构建一个富
,已经给了 Foo.SomeFoo
字段的默认值...正如你猜测,这是一个递归的噩梦。
既然你可以创建一个空引用类,并从实际创建紧跟在类的一个实例不要,没有任何问题;你可以叫新富()
和 Foo.SomeFoo
将只是空。没有递归必要的。
补遗:当你考虑这个,如果你还是有疑惑,我想其他的答案有考虑到它(相同的基本问题,不同的方法),另一种好办法 - 当程序分配内存为富
,怎么它应该做的呢?什么是的sizeof(美孚)
在富
包含了一些东西,然后又是整个富
?你不能做到这一点。
相反,如果它是一个类,那就只需要分配几个字节的引用富
,而不是实际的富
,而且也没有问题。
For sometime now, I have been trying to wrap my head around the reason why some "cannibal" classes are allowed to compile.
Before I continue, perhaps I should explain what I call a "cannibal" class. Not sure if I just invented that term or if it has been around for a while or even if I am using it correctly but that is not important right now.
I basically call a cannibal class a class that consumes itself. In other words a class whose interface declares members of its own type. For example:
class Foo
{
public Foo SomeFoo;
}
As you can see above, class Foo has a member of type Foo (itself).
Now, the first time I saw this (looong time ago) I didn’t thing it was going to compile but it to my surprise it does compile. The reason why I didn’t thing this would compile is because to me this screams some type of recursive nightmare.
To complicate things a little further, I decided to try the same thing but making the class a struct such as:
struct Foo
{
public Foo SomeFoo;
}
Unfortunately, this does not compile, instead you get error: Struct member 'Foo.SomeFoo' of type 'Foo' causes a cycle in the struct layout
To me, a compile error makes more sense that no error but I am sure there most be a logical explanation to this behavior so I was wondering if anyone of you guys could explain this behavior.
Thanks.
解决方案The reason you can't design a struct like this is because structs have to be initialized when they are allocated with some default values. So, when you have a struct Foo
like you described and you create a Foo
...
Foo x; // x = default(Foo)
it calls the default constructor for Foo
. However, that default constructor has to give a default value for the Foo.SomeFoo
field.
Well, how's it find that? It has to call default(Foo)
. Which, in order to construct a Foo
, has to give a default value for the Foo.SomeFoo
field... As you surmised, this is a recursive nightmare.
Since you can create a null reference to a class, and refrain from actually creating an instance of the class immediately, there's no problem; you can call new Foo()
and Foo.SomeFoo
will just be null. No recursion necessary.
ADDENDUM: When you're thinking about this, if you're still confused, I think the other answers have another good way of considering it (same essential problem, different approach) -- when the program allocates memory for a Foo
, how's it supposed to do it? What's sizeof(Foo)
when Foo
contains some stuff, and then another whole Foo
? You can't do that.
Instead, if it were a class, it would just have to allocate a couple bytes for a reference to a Foo
, not an actual Foo
, and there's no problem.