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?
Upcasting is the typecasting of a child object to a parent object. Upcasting can be done implicitly. Upcasting gives us the flexibility to access the parent class members but it is not possible to access all the child class members using this feature.
In Upcasting, we assign a parent class reference object to the child class. In Java, we cannot assign a parent class reference object to the child class, but if we perform downcasting, we will not get any compile-time error. However, when we run it, it throws the "ClassCastException".
4 Answers. 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.
It is the process to create the derived class's pointer or reference from the base class's pointer or reference, and the process is called Upcasting. It means the upcasting used to convert the reference or pointer of the derived class to a base class.
"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.
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With