So far, the only type of animal we’ve defined is a cat (via the ‘Cat’ class). Our ‘Cat’ class also requires us to name our cats. Finally, our ‘Cat’ class performs rendering to the web page. However, what if we wanted to introduce other animals? How should we implement dogs, pandas, and rhinos?
While the simple answer is that we can just copy, paste, and modify our code from Cat.jspp into Dog.jspp, Panda.jspp, and Rhino.jspp, this is usually not good programming. Instead, we might notice that there is a lot of repetition in the design; all the animals need a name, all the animals need to be rendered to our web page, and all the animals can be categorized together. Therefore, we can define the behaviors we need for animals in general (such as rendering to a web page) and have all our animal classes “inherit” this common behavior. Furthermore, some animals might not need names; for example, domesticated animals like cats and dogs might need names, but we might not want to name our pandas and rhinos.
First, let’s start by examining Cat.jspp. What data or behavior in Cat.jspp should be common to all animals?
From what we’ve defined so far, it should only be the render() method. We’ll use that as the basis for understanding inheritance. Earlier, we created an Animal.jspp file. It’s currently empty so open it and let’s define an ‘Animal’ class:
external $;
module Animals
{
class Animal
{
var $element = $(
"""
<div class="animal">
<i class="icofont icofont-animal-cat"></i>
</div>
"""
);
void render() {
$("#content").append($element);
}
}
}
This works well as a basic template. However, a keen observer will notice we have a problem: the $element field will always render a cat icon. We’ll get back to this later, but, first, let’s change Cat.jspp to inherit from our new ‘Animal’ class:
external $;
module Animals
{
class Cat : Animal
{
string _name;
Cat(string name) {
_name = name;
}
}
}
We removed the $element field and render() method from Cat.jspp and we added this to the class declaration:
class Cat : Animal
The colon syntax specifies the inheritance relationship. In this case, our ‘Cat’ class inherits from the ‘Animal’ class. In other words, our ‘Cat’ class extends the ‘Animal’ class; everything that belongs to the ‘Animal’ class (fields, getters/setters, methods, etc) also belongs to the ‘Cat’ class.
In inheritance, our ‘Cat’ class is known as the “subclass” or “derived class” of ‘Animal’. ‘Animal’ may be referred to as the “superclass” or “base class.”
If you try to compile your code right now, you’ll still see the cats rendered to the page exactly as before, but, if you hover your mouse over any of the cats, you will not see its respective name. The render() method on ‘Cat’ is now derived from the ‘Animal’ class. Since our ‘Animal’ class does not take names (as we want to be able to generalize the class for wild animals like pandas and rhinos), its render() method likewise does not render the HTML ‘title’ attribute needed to show a name on mouse over. However, we can make this behavior possible. In order to do that, it requires explanation of access modifiers, which we will now cover.
Similar Reads
JS++ | Interfaces
As we learned in the chapter on subtype polymorphism, an operation defined for a supertype can be safely substituted with its subtypes. As a result, operations defined for 'Animal' objects can safely accept 'Cat' or 'Dog' objects. Furthermore, we mentioned that you should not confuse subtyping with
7 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++ | 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
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++ 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++ | 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++ | The 'final' Modifier
In the context of virtual methods discussed in the previous section, the 'final' modifier allows us to form an even more correct specification. When applied to overridden methods, the 'final' modifier allows us to specify that this method override is the last and cannot be further overridden. This p
2 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++ | 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++ | Upcasting and Downcasting
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
3 min read