以下课程:
public class Parent {
//Parent members
}
public class ChildA : Parent {
//ChildA members
}
public class ChildB : Parent {
//ChildB members
}
如果我将ChildA或ChildB实例转发到Parent实例,那么我无法访问其成员,但是他们的成员仍然在那里,因为如果我沮丧并尝试再次访问其成员,我会发现他们仍然有他们的数据。
我认为这意味着父实例不断为子类分配内存。
这是否意味着当我实例化一个父类,它为子类成员分配内存时,还是在我投射时才发生?
如果我们使用强制转发前进和后退,父母是否可以为多个孩子分配内存?
答案 0 :(得分:14)
在上面描述的情况下,强制转换不会影响从基类转换为子类时分配的内存,反之亦然。
如果您实例化Parent,则内存中将包含Parent对象。如果将其转换为其中一个子类,它将失败并显示InvalidCastException
。
如果你实例化任何一个孩子,你将在内存中有一个子对象。您可以将其强制转换为父级,然后再返回。在任何一种情况下,内存分配都不会改变。
此外,如果您实例化ChildA,强制转换为Parent,然后尝试强制转换为ChildB,您将获得InvalidCastException
答案 1 :(得分:5)
<强>&#34;正常&#34;参考类型的上传和下调
对于引用类型,转换变量不会更改已在堆上分配的对象的类型,它只会影响引用该对象的变量的类型。
所以不,没有任何额外的堆开销与转换引用类型(即来自类的对象实例)。
考虑以下类层次结构:
public class Fruit
{
public Color Colour {get; set;}
public bool Edible {get; set;}
}
public class Apple : Fruit
{
public Apple { Color = Green; Edible = true; KeepsDoctorAtBay = true;}
public bool KeepsDoctorAtBay{get; set;}
}
当与向上转发和向下转发一起使用时:
堆上只有一个分配,即初始var foo = new Apple()
。
在各种变量赋值之后,所有三个变量foo
,bar
和baz
都指向同一个对象(堆上的Apple
实例)。
向上转换(Fruit bar = foo
)只会限制变量对Fruit
方法和属性的可用访问权限,如果(Apple)bar
向下转换成功,则所有方法,属性和事件都成功转化类型将可用于变量。如果向下转换失败,将抛出InvalidCastException
,因为类型系统将在运行时检查堆对象的类型与变量的类型的兼容性。
转化运算符
根据tolanj的评论,如果explicit conversion operator替换了默认的引用类型,那么关于堆的所有赌注都将被取消。
例如,如果我们添加一个不相关的类:
public class WaxApple // Not inherited from Fruit or Apple
{
public static explicit operator Apple(WaxApple wax)
{
return new Apple
{
Edible = false,
Colour = Color.Green,
KeepsDoctorAtBay = false
};
}
}
可以想象,WaxApple的explicit operator Apple
可以做任何事情,包括在堆上分配新对象。
var wax = new WaxApple();
var fakeApple = (Apple)wax;
// Explicit cast operator called, new heap allocation as per the conversion code.
答案 2 :(得分:4)
通过“父类的眼睛”,(向下)强制转换只是视图到类的实例上。因此,您既不会丢失也不会通过强制转换添加任何信息或内存,只需引用已为原始实例分配的相同内存即可。这就是为什么你仍然可以访问ChildA
变量中Parent
的{{1}}成员的原因(例如通过反思)。信息仍然存在,根本不可见。
因此,您没有两个内存 - 分配,而是有两个内存 - 引用。
但是请注意,如果你提供自己的演员表,那么不适用。从ChildA
到ChildB
。这样做通常看起来或多或少类似于:
public static explicit operator ChildA(ChildB b)
{
var a = new ChildA((Parent)b);
/* set further properties defined in ChildA but not in ChildB*/
}
这里有两个完全不同的实例,一个类型为ChildA
,另一个类型为ChildB
,它们都占用了自己的内存。
答案 3 :(得分:1)
我认为这意味着父实例不断为子类分配内存。
不,因为Parent
班级不知道它的孩子。
var a = new ClassA();
.NET
为ClassA
的所有成员分配内存。
var b = (Parent)a;
.NET
对记忆没有任何作用。 a
和b
指向相同的内存块(已分配给ClassA
)。