Reputation: 189
For the following classes:
public class Parent {
//Parent members
}
public class ChildA : Parent {
//ChildA members
}
public class ChildB : Parent {
//ChildB members
}
If I upcast ChildA or ChildB instance to a Parent instance, then I can't accesses their members, but their members are still there, because if I downcast and try to access their members again I will find that they still have their data.
I think this means that the Parent Instance keep allocating memory for the Child classes.
So does this mean when I instantiate a Parent Class that its allocating memory for the child classes members, or is that just happening when I cast?
And is it possible for a parent to allocate memory for more than one child if we go backward and forward with casting?
Upvotes: 9
Views: 2655
Reputation: 107317
"Normal" Upcasting and Downcasting of Reference Types
For reference types, casting variables doesn't change the type of the object already allocated on the heap, it just affects the type of the variable which references the object.
So no, there isn't any additional heap overhead with casting reference types (i.e. object instances from classes) provided that there are no custom conversion operators involved (See below, tolanj's comment).
Consider the following class hierarchy:
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;}
}
Which, when used with both upcasting and downcasting:
There is only ever one allocation on the heap, which is the initial var foo = new Apple()
.
After the various variable assignments, all three variables, foo
, bar
and baz
point to the same object (an Apple
instance on the heap).
Upcasting (Fruit bar = foo
) will simply restrict the variable's available access to only Fruit
methods and properties, and if the (Apple)bar
downcast is successful all methods, properties and events of the downcast type will be available to the variable. If the downcast fails, an InvalidCastException
will be thrown, as the type system will check the type of the heap object's compatability with the variable's type at run time.
Conversion Operators
As per tolanj's comment, all bets about the heap are off if an explicit conversion operator replaces the default casting of reference types.
For instance, if we add an unrelated class:
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
};
}
}
As you can imagine, WaxApple's explicit operator Apple
can do whatever it likes, including allocate new objects on the heap.
var wax = new WaxApple();
var fakeApple = (Apple)wax;
// Explicit cast operator called, new heap allocation as per the conversion code.
Upvotes: 7
Reputation: 4679
In the case you describe above, casting does not affect the memory that is allocated when casting from base to sub class and vice versa.
If you instantiate a Parent you will have a Parent object in memory. If you cast that to either of the child classes it will fail with an InvalidCastException
.
If you instantiate either child you will have a child object in memory. You can cast this to the Parent and then back again. The memory allocation does not change in either case.
Additionally, if you instantiate a ChildA, cast to Parent and then attempt to cast to ChildB, you will get an InvalidCastException
Upvotes: 14
Reputation: 24913
I think this means that the Parent Instance keep allocating memory for the Child classes .
No, because Parent
class does not know about it's children.
var a = new ClassA();
.NET
allocates memory for all members of ClassA
.
var b = (Parent)a;
.NET
does not do anything with memory. a
and b
point to the same memory block (allocated for ClassA
).
Upvotes: 1
Reputation: 37050
A (down-)cast is nothing but a view onto an instance of a class by the "eyes of the parent class". Thus you´re neither losing nor adding any information nor memory by casting, you simply reference the same memory allready allocated for the original instance. This is the reason why you can still access (e.g. by reflection) the members of ChildA
in the variable of type Parent
. The information still exists, it is simply not visible.
So instead of having two memory-allocations you have two memory-references.
However be aware that this does not apply if you provide your own cast, e.g. from ChildA
to ChildB
. Doing so will typically look more or less similar to this:
public static explicit operator ChildA(ChildB b)
{
var a = new ChildA((Parent)b);
/* set further properties defined in ChildA but not in ChildB*/
}
Here you have two completely different instances, one of type ChildA
and one of type ChildB
which both consume their own memory.
Upvotes: 4