![]() | This article includes a list ofgeneral references, butit lacks sufficient correspondinginline citations. Please help toimprove this article byintroducing more precise citations.(August 2008) (Learn how and when to remove this message) |
Inclass-based programming,downcasting, or type refinement, is the act ofcasting abase orparent class reference, to a more restrictedderived class reference.[1] This is only allowable if the object is already an instance of the derived class, and so this conversion is inherently fallible.
In many environments,type introspection can be used to obtain the type of an object instance at runtime, and then use this result to explicitly evaluate itstype compatibility with another type. The possible results of comparingpolymorphic types—besides them being equivalent (identical), or unrelated (incompatible)—include two additional cases: namely, where the first type is derived from the second, and then the same thing but swapped the other way around (see:Subtyping § Subsumption).
With this information, a program can test, before performing an operation such as storing an object into a typed variable, whether that operation is type safe, or whether it would result in an error. If the type of the runtime instance is derived from (a child of) the type of the target variable (therefore, the parent), downcasting is possible.
Some languages, such asOCaml, disallow downcasting.[2]
publicclassFruit{}// parent classpublicclassAppleextendsFruit{}// child classpublicstaticvoidmain(String[]args){// The following is an implicit upcast:Fruitparent=newApple();// The following is a downcast. Here, it works since the variable `parent` is// holding an instance of Apple:Applechild=(Apple)parent;}
// Parent class:classFruit{public:// Must be polymorphic to use runtime-checked dynamic-cast.virtual~Fruit()=default;};// Child class:classApple:publicFruit{};intmain(intargc,constchar**argv){// The following is an implicit upcast:Fruit*parent=newApple();// The following is a downcast. Here, it works since the variable `parent` is// holding an instance of Apple:Apple*child=dynamic_cast<Apple*>(parent);}
Downcasting is useful when the type of the value referenced by the Parent variable is known and often is used when passing a value as a parameter. In the below example, the method objectToString takes an Object parameter which is assumed to be of type String.
publicstaticStringobjectToString(ObjectmyObject){// This will only work when the myObject currently holding value is string.return(String)myObject;}publicstaticvoidmain(String[]args){// This will work since we passed in String, so myObject has value of String.Stringresult=objectToString("My String");ObjectiFail=newObject();// This will fail since we passed in Object which does not have value of String.result=objectToString(iFail);}
In this approach, downcasting prevents the compiler from detecting a possible error and instead causes a run-time error.Downcasting myObject to String ('(String)myObject') was not possible at compile time because there are times that myObject is String type, so only at run time can we figure out whether the parameter passed in is logical. While we could also convert myObject to a compile-time String using the universal java.lang.Object.toString(), this would risk calling the default implementation of toString() where it was unhelpful or insecure, and exception handling could not prevent this.
In C++, run-time type checking is implemented throughdynamic_cast. Compile-time downcasting is implemented bystatic_cast, but this operation performs no type check. If it is used improperly, it could produce undefined behavior.
A popular example of a badly considered design is containers oftop types,[citation needed] like theJava containers beforeJava generics were introduced, which requires downcasting of the contained objects so that they can be used again.