我想知道在创建派生类的实例时,如何在派生类之前自动实例化基类。
我只想知道基类的成员如何占用内存,子类的引用如何访问它们。
答案 0 :(得分:3)
让我们举一些例子:
class A
{
int x;
int y;
}
class B: A
{
int c;
}
如果创建A
的新实例,则会在堆上创建一块内存。这个内存占用8个字节; x
为4个字节,y
为4个字节。 (我知道,更多的内存是为它的类型保留的,等等,但我会把它留在这个范围之外)。
如果您创建B
的新实例,则会创建anohter内存。不是两个,只有一个。所以没有儿童实例或任何。这段内存的长度为12个字节(x
为4个字节,y
为4个字节,新字段为z
为4个字节。
当在堆上创建一块内存时,它将始终用零填充。因此,所有fieds都将具有默认值,在本例中为0
。
如果两个类都有一个公共无参数构造函数,则会自动调用这些构造函数。
class A
{
int x;
int y;
public A()
{
x = 1; y = 2;
}
}
class B: A
{
int c;
public B()
{
z = 3;
}
}
创建B
的新实例时,将调用B
的构造函数。构造函数做的第一件事是调用A
的构造函数。 A
会将其字段x
和y
设置为1
和2
。然后程序返回B
的构造函数,该构造函数将使用值z
初始化3
。
B
的构造函数也可以写成(表示B
正在调用其基类A
的构造函数):
public B()
: base()
{
z = 3;
}
答案 1 :(得分:2)
该对象一次创建:字段的空间是根据X : Y : Z
需要X
中声明的字段总和空间的知识来分配的, Y
,Z
(和任何object
开销,作为Z
的隐含基础。这些字段是继承的,因此X
是Z
。
它们是自下而上初始化的,因为是构造函数的工作方式;如果我们写:
class A : B
{
private int _a = 1;
public A() { Console.WriteLine("A"); }
}
class B {
private int _b = 1;
public B() { Console.WriteLine("B"); }
}
然后我们得到(B
):
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed
{
.maxstack 8
L_0000: ldarg.0
L_0001: ldc.i4.1
L_0002: stfld int32 B::_b
L_0007: ldarg.0
L_0008: call instance void [mscorlib]System.Object::.ctor()
L_000d: ldstr "B"
L_0012: call void [mscorlib]System.Console::WriteLine(string)
L_0017: ret
}
和A
:
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed
{
.maxstack 8
L_0000: ldarg.0
L_0001: ldc.i4.1
L_0002: stfld int32 A::_a
L_0007: ldarg.0
L_0008: call instance void B::.ctor()
L_000d: ldstr "A"
L_0012: call void [mscorlib]System.Console::WriteLine(string)
L_0017: ret
}
请注意,在运行自己的本地构造函数代码之前,它会调用基础构造函数。另请注意,字段初始化程序甚至在此之前就已存在。
答案 2 :(得分:0)
对此的一个简单解释是认为继承为复制机
所以我们定义2个类
class Base
{
}
class Child : Base
{
}
现在你要创建一个child对象。 Child有自己的字段,但由于它继承自base,因此必须复制其基类的所有字段,从而自动创建。
类是对象的模板,继承只是可以在创建新模板时附加的可恢复模板。