子class的对象是否也分配了父class的对象?

Does an object of a subclass also allocate an object of the parent class?

Class A
{
    int X {get;set;}
}
Class B : A
{
    int Y {get;set;}
}

B myB;

为了论证,说A类型的对象是4字节,B类型的对象是4字节。

B 是allocated/initialized/constructed,它的内容存储在堆上。

B的大小是8字节加上X和Y的指针串联,还是两个4字节的对象?

像下面这样的情况还是会导致两个对象吗?

Class A {}
Class B
{
    A myA;
}

B myB;

我是否可以假设,如果这些情况导致不同的数据,继承使用的堆分配比构造更少,因为附加包含的对象分配了它的数据——并且堆在它的包含对象之外分配了这个数据?

我可以得出结论,构造比继承的内存效率低得多吗?

澄清: 初始化 subclass 类型的对象时,该对象的父 class 属性的字节是否与 subclass 的属性的字节一起存储? B 是存储指向 A 的指针还是直接存储 A 的属性?如果它存储指向 A 实例的指针,那么它在内存中就和它在内存中一样取而代之的是 A 类型的 属性。

加法: 据说在第一个示例中 B 的数据也包含 A 的数据。 子classed对象分配内存时是分两次分配还是一次分配?

在第二个示例中,您分配了两次内存:一次是针对包含的 属性 类型 A 对象,另一次是针对对象 class B,所以我假设您有两个不同的内存分配和两个不同的对象,指针指向 B 中的 A。

如果一个子class只为其所有属性及其所有继承属性的整个大小分配一次内存,并内联存储所有这些信息,那么这不是一种更好的内存分配方法吗比为一个对象分配多个对象?

假设您是 运行 x86 架构上的 .NET,空对象的开销为 8 个字节(最小大小为 12 个字节)。这意味着 new object() 将占用内存中的 12 个字节。

考虑以下 class 结构:

public class Parent // overhead 8 bytes
{
    int a, b, c, d; // int 4 bytes * 4 = 16 bytes
}

public class Child : Parent // inherits everything
{ }

var parent = new Parent(); // 24 bytes
var child = new Child(); // 24 bytes [NOTE: this is a SINGLE object of type Child, not two objects Parent+Child]

它们是相同大小的对象,因为 Child 没有声明任何其他字段。

以下 class 结构代替:

public class Composable // overhead 8 bytes
{
    int a, b, c, d; // int 4 bytes * 4 = 16 bytes
}

public class Composite // overhead 8 bytes
{
    Composable c = new Composable(); // 4 bytes (reference on the heap)
}

var composable = new Composable(); // 24 bytes
var composite = new Composite(); // 36 bytes (24 + 12) [NOTE: this creates TWO different objects, with one referencing the other]

由于以下两个原因,开销会略高:"empty object" 创建新对象的开销和为堆栈中的内部对象分配的引用。

回答你的问题:是的,组合比继承需要稍微多一点的内存,但是数字真的太小了,不用担心。

关于您的其他问题

When initializing an object of subclass type, are the bytes of that object's parent class's properties stored alongside the bytes of the subclass's properties?

是的,正如继承示例清楚地表明的那样:我们有一个对象包含其 class 和任何继承的 class.

的所有字段

It was said that the data of B contains the data of A also in the first example. Are there two allocations or one allocation when allocating the memory of a subclassed object?

一次分配

In the second example, you're allocating memory twice: once for the contained property object of type A and once again for the object class B, so I'm presuming that you have two distinct memory allocations and two distinct objects with a pointer to A inside B.

你几乎是正确的,只有当你真的创建那个对象时才会发生第二次分配。在您的示例中,您只是声明一个字段 A myA:这占用 4 个字节的内存(在 x86 中),仅此而已。当你创建那个对象时它会占用更多的内存(例如A myA = new A()

If a subclass only allocates memory once for the entire size of all its properties and all its inherited properties, and stores all that information inline, then wouldn't that make it a superior memory allocation approach than allocating multiple objects for one object?

组合与继承有不同的特点,我不认为它对现实世界有任何影响,但是是的,继承比组合占用稍微更少的内存。

参考:OF MEMORY AND STRINGS by C#...呃...我是说 Jon Skeet。

When initializing an object of subclass type, are the bytes of that object's parent class's properties stored alongside the bytes of the subclass's properties?

是的,可能吧。 C# 本身并没有详细说明内存模型(如果有的话;我对规范不是很熟悉)。我相当确定这是实现定义的。但是,包含对其 Base 的完全独立实例的引用的 Derived 实例没有意义,原因如下:

如果 Base 是抽象的,那么内存模型不仅允许而且实际上需要创建抽象实例 class。

在 IL 级别,指向 Derived 的托管指针(实际引用)可以放置在指向 Base 的托管指针的任何地方。现在,我们可以排除运行时执行某种类型的转换(例如引用 Base 实例),因为那样会丢失 RTTI。但是我们知道我们可以在运行时将 Base 引用转换为 Derived 实例,因此它不能修改指针。

但是,当尝试通过 Derived 的实例访问和修改 Base 的字段时,这会引起麻烦。在那种情况下,CLR 必须将字段信息附加到实例 v-table。当然不是不可能,但到那时 CLR 实现者只会竭尽全力让事情变得更加困难。据我所知,以这种方式做事并没有真正的好处(除非您希望能够在运行时更改继承层次结构,而 C# 和 CLR 都不允许这样做)。

它还会通过添加另一层间接层来招致很多相当无意义的性能损失,这本可以通过直接在 Derived 的实例中包含 Base 的字段来避免。