上传及其对堆的影响

时间:2017-11-20 10:47:50

标签: c# oop inheritance upcasting

以下课程:

public class Parent {
//Parent members
}

public class ChildA : Parent {
//ChildA members
}

public class ChildB : Parent {
//ChildB members
}

如果我将ChildA或ChildB实例转发到Parent实例,那么我无法访问其成员,但是他们的成员仍然在那里,因为如果我沮丧并尝试再次访问其成员,我会发现他们仍然有他们的数据。

我认为这意味着父实例不断为子类分配内存。

这是否意味着当我实例化一个父类,它为子类成员分配内存时,还是在我投射时才发生?

如果我们使用强制转发前进和后退,父母是否可以为多个孩子分配内存?

4 个答案:

答案 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;}
}

当与向上转发和向下转发一起使用时:

Example of variables pointing to same heap object

堆上只有一个分配,即初始var foo = new Apple()

在各种变量赋值之后,所有三个变量foobarbaz都指向同一个对象(堆上的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}}成员的原因(例如通过反思)。信息仍然存在,根本不可见。

因此,您没有两个内存 - 分配,而是有两个内存 - 引用

但是请注意,如果你提供自己的演员表,那么适用。从ChildAChildB。这样做通常看起来或多或少类似于:

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();

.NETClassA的所有成员分配内存。

var b = (Parent)a;

.NET对记忆没有任何作用。 ab指向相同的内存块(已分配给ClassA)。