JS++ | Upcasting and Downcasting
Last Updated :
30 Aug, 2018
Now that we understand both subtyping and static versus dynamic polymorphism, we can learn about upcasting and downcasting.
Upcasting and downcasting is based on type relationships. In other words, if you have data of type 'Animal', you can "downcast" it to its subtype 'Dog'. Conversely, if you have data of type 'Dog', you can "upcast" it to its supertype 'Animal'. However, you cannot cast data of either type to 'int' because there is no type relationship between 'int' and 'Animal' or 'Dog'.
Since we are now equipped with an understanding of compile-time versus runtime polymorphism, and why and how the compiler resolved the 'render' method when the data type was specified as 'Animal', let's restore our main.jspp code:
import Animals;
Animal cat1 = new Cat("Kitty");
cat1.render();
Animal cat2 = new Cat("Kat");
cat2.render();
Animal dog = new Dog("Fido");
dog.render();
Animal panda = new Panda();
panda.render();
Animal rhino = new Rhino();
rhino.render();
As you'll recall, this is the code that rendered all our animals, but we no longer got the animal names on mouse over. One way to remedy this is with a downcast:
import Animals;
Animal cat1 = new Cat("Kitty");
((Cat) cat1).render();
Animal cat2 = new Cat("Kat");
((Cat) cat2).render();
Animal dog = new Dog("Fido");
((Dog) dog).render();
Animal panda = new Panda();
panda.render();
Animal rhino = new Rhino();
rhino.render();
The syntax for a type cast is:
(type) expression
For example:
(int) 100
The reason there are extra parentheses in our revised main.jspp code is because we want the type cast to take precedence so that the cast occurs before the 'render' method is called. See the JS++ operator precedence table for more details.
If you compile and run the code now, you should see that the cats and dogs once again show their names when you hover your mouse over their icon.
To illustrate upcasting, we can also cast one of our cats to the 'Animal' type. Calling the 'render' method on this cat will mean it uses the 'Animal' class render() method which will not include the name:
import Animals;
Animal cat1 = new Cat("Kitty");
((Cat) cat1).render();
Cat cat2 = new Cat("Kat");
((Animal) cat2).render();
Animal dog = new Dog("Fido");
((Dog) dog).render();
Animal panda = new Panda();
panda.render();
Animal rhino = new Rhino();
rhino.render();
Notice that I changed the type of 'cat2' back to 'Cat' in order to illustrate upcasting. From there, I upcast 'cat2' to 'Animal'. If you compile the code now, you will notice the first cat ("Kitty") has its name shown on mouse over, but the second cat ("Kat") does not have the same behavior.
While we were able to resolve the correct 'render' method using casts, this is not the most elegant way to resolve the method. For example, if we had an array of 'Animal' objects, our loop would be nested with 'if' statements performing 'instanceof' checks and subsequent type casts. This is not ideal and leads to hard-to-read code. There is a more elegant way: virtual methods.
Similar Reads
JS++ | Static Members and "Application-Global" Data
Up until now, all of the fields and methods that we've declared have belonged to class instances. Static members can also be added to a class. A static member is initialized at program start and is available to all instances of a class. As an example, we might want to keep a count of the number of '
4 min read
JS++ | Classes, OOP, and User-defined Types
Up until now, we've been declaring variables, looping over data, and writing 'if' and other conditional statements. These operations comprise the "imperative programming" paradigm where we describe "how" a program operates step by step (or, more specifically, statement by statement). Oftentimes, in
6 min read
JS++ | Fields and Methods
Creating and Rendering an Animal Open 'src/Animals/Cat.jspp' and enter the following code: external $; module Animals { class Cat { void render() { var $element = $( """ <div class="animal"> <i class="icofont icofont-animal-cat"></i> </div> """ ); $("#content").append($elemen
9 min read
JS++ | Types in JavaScript
In this chapter, we're going to explore JavaScript programming styles and how developers worked with types in JavaScript (rather than JS++). This chapter will help you understand the next chapters which explain the JS++ type system in detail. In this tutorial, we will be using the Google Chrome web
10 min read
JS++ Getters and Setters
In our previous example, we defined a 'setName' method that sets a class 'name' field we declared. A method whose sole responsibility is to write to or modify a class field is known as a "setter" or "setter method." Conversely, a method whose sole responsibility is to return the current data of a cl
4 min read
JS++ | Abstract Classes and Methods
We have explored virtual methods and 'overwrite' (early binding) and 'override' (late binding) which allow us to define base implementations for a method and more specific implementations of the method in subclasses. However, what do we do if there is no relevant base implementation that makes sense
3 min read
JS++ | Functions
A function is a section of code which contains a set of instructions, where the instructions describe how a particular task is to be accomplished. Functions are declared and may then be called one or more times. Declaring a function involves specifying the instructions that the function will contain
10 min read
JS++ | Static vs. Dynamic Polymorphism
Static polymorphism is polymorphism that occurs at compile time, and dynamic polymorphism is polymorphism that occurs at runtime (during application execution). An aspect of static polymorphism is early binding. In early binding, the specific method to call is resolved at compile time. (JS++ also su
4 min read
JS++ | Access Modifiers and 'super'
Access modifiers allow us to change the "visibility" and "access privileges" of a class (or module) member. These are best understood by example. JS++ has three access modifiers: private, protected, and public. A private member is the least permissive. If a member is declared as 'private' it can onl
15 min read
JS++ | Constructors
In our cat example, we've been able to instantiate our cat and provide a name separately. However, it may be desirable to require the cat to be named at instantiation so that we don't accidentally forget to name a cat. Constructors allow us to control instantiation. By default, JS++ provides a const
3 min read