Inheritance - Parent class and Child class

Inheritance is one of the most useful instruments of the Object Oriented Programming - OOP.
Inheritage is a characteristic of the classes that lets you to transfer /use properties, constants and methods from one class to another, in an hierarchical structure.
Inheritance enables you to define a base class (also called parent class) and create one or more classes derived from it.
A class that inherits from another is said to be a subclass of it, or child class.
A child class inherits all public and protected properties and methods from the parent, and can use them in it's own code and transmits them when an instance of the child subclass is created. As in nature, children inherit the parent's genes.

Here's how to use inheritance in ActionScript 3 programming. We will create a base class, named "Mover", which can be used to move objects in a Flash presentation. The object that must be moved and the values for it's speed on the x/y axis are passed in arguments when the object instance of the class is created (more explanations are found in the code).

// Create the package (without name)
package {
  // Import the predefined ActionScript 3 classes used in this class
  import flash.events.Event;
  import flash.display.MovieClip;

  // Start defining the Mover class
  public class Mover
  {
    // Setting properties
    // 'insMC' - for the MovieCplip instance, 'xVel' - for horizontal speed, 'yVel' - for vertical speed
    public var insMC:MovieClip;
    public var xVel:Number;
    public var yVel:Number;

    // Create the constructor, takes as arguments a MovieClip instance and 2 numerical values
    function Mover(inMC:MovieClip, xV:Number, yV:Number)
    {
      // set the properties values with the values from parameters
      this.insMC = inMC;
      this.xVel = xV;
      this.yVel = yV;
    }

    // Create a method with "protected" attribute (can be used only in this class and it's sub-classes)
    protected function updatePosition(evtObj:Event):void
    {
      // Increments the 'x' and 'y' distance of the  "insMC" with the values from the "xVel" and "yVel" properties
      this.insMC.x += this.xVel;
      this.insMC.y += this.yVel;
    }

    // Define a public method used to start the moving
    public function startMove():void
    {
      // Apply an event listener ENTER_FRAME to 'insMC'
      // this calls the protected method, updatePosition
      this.insMC.addEventListener(Event.ENTER_FRAME, this.updatePosition);
    }

    // Define a public method to stop the moving
    public function stopMove():void
    {
      // removes the event listener registered in "startMove()"
      insMC.removeEventListener(Event.ENTER_FRAME, this.updatePosition);
    }
  }
}

- To test this class, follow these steps:
  1. Open from File -> New a new "ActionScript 3.0 Class document". On the window that opens, type Mover for the class name. Delete the code that initially appears in the document and copy the code above, then save it with the name "Mover.as".
  2. Open a new Flash document, draw a shape on the stage (for example a circle) and convert it into a MovieClip (from Modify - Convert to Symbol, make sure the middle point from Registration is checked, this sets its center of coordinates).
    Open the Properties panel and give the name "sfer" to the instance on the stage (the shape converted into a Movie Clip), in the top box, where "<Insance Name>" is written.
  3. Right-Click on Frame 1 in the Timeline, choose Actions and add the following code in the Actions panel:
    // Create an instance of Mover class 
    var obj:Mover = new Mover(sfer, 2, 3);
    obj.startMove();         // Call the "startMove()" method
    
    // Call the "stopMove" method after 3 seconds (3000 milliseconds)
    // "stopMove" deletes the record of the ENTER_FRAME event, and will stop the motion
    setTimeout(obj.stopMove, 3000);
    
      - "setTimeout()" is used to call a function /method after a specified time has passed (in milliseconds).
  4. Save the Flash document in the same folder as "Mover.as", then press Ctr+Enter. The Flash Player will show a presentation like this (click on the image).
    as3-inheritance_parent_child_class0
- This class moves the object in a single direction until it leaves the Stage (or until a "stopMove()" command is given), but maybe we want that some objects to move continuously inside the Stage area, bouncing from its border. Instead of creating a new class or modifying /ruining this one, we can define a child subclass that extends the "Mover" class.
In the child class we import the parent class (Mover), then this child class will inherit the properties and methods used for motion.
We only define the new instructions to change the motion direction when the object reaches the borders.

• To create a child class, you must use the extends keyword in the subclass declaration, followed by the name of the parent class:
package {
  import ParentClass;
  attribute class ChildClass extends ParentClass {
    // The code of the ChildClass
  }
}
- When a class uses the properties and /or methods of another class, that class must be included (imported) with the import instructions.

Here's how to create a child class (named "MoverChild") that extends the "Mover" class (defined above).
Open another "ActionScript 3.0 Class" document, give it the class name MoverChild, delete its initial code and copy the following code:
// Create the package (without name)
package {
  // Import classes whose properties and methods will be accessed in this class
  import flash.display.MovieClip;
  import flash.events.Event;
  import Mover;               // Import the parent class

  // Start defining the child subclass
  public class MoverChild extends Mover
  {
    // Constructor (receives 3 arguments, a MovieClip object and 2 numbers)
    public function MoverChild(inMC:MovieClip, xV:Number, yV:Number)
    {
      // Call the Constructor of the parent class, with its parameters for arguments
      super(inMC,xV,yV);
    }

    // method to change the motion direction when the object reaches the border
    // With 4 if() instructions to verify the object's position for each side
    private function bounceAtBorder():void
    {
      // Verify if the object has reached the right edge
      // Substracts half the object's width (this.insMC.width/2) from the Stage's width (this.insMC.stage.stageWidth)
      // (half because we created the MovieClip object with the registration center in the middle)
      if(this.insMC.x > this.insMC.stage.stageWidth-(this.insMC.width/2))
      {
        // Set up the 'x' distance with the value resulted by the Stage's width minus half the object's width
        // Turns negative the value of the property used for horizontal motion (to change direction) 
        this.insMC.x = this.insMC.stage.stageWidth-(this.insMC.width/2);
        xVel *= -1;
      }

      // Verify if the object has reached the bottom edge 
      // Substracts from the Stage's height (this.insMC.stage.stageHeight) half of the object's height (this.insMC.height/2)
      if (this.insMC.y > this.insMC.stage.stageHeight-(this.insMC.height/2))
      {
        // Set up the 'y' distance with a the value resulted by the Stage's height minus half the object's height
        // Turns negative the value of the property used for vertical motion (to change direction)
        this.insMC.y = this.insMC.stage.stageHeight-(this.insMC.height/2);
        yVel *= -1;
      }

      // Verify if the object has reached the left edge
      // (the 'x' distance smaller than half the object's width)
      if (this.insMC.x < this.insMC.width/2)
      {
        // Set up the value for 'x' distance half the object's width
        // Turns negative the property's value used for horizontal motion speed
        this.insMC.x = this.insMC.width/2;
        xVel *= -1;
      }

      // Verify if the object has reached the top edge
      //(the 'y' distance smaller than half the object's height)
      if (this.insMC.y < this.insMC.height/2)
      {
        // Set up the value for 'y' distance half the object's height
        // Turns negative the property's value for vertical motion speed
        this.insMC.y = this.insMC.height/2;
        yVel *= -1;
      }
    }

    // Rewrite the "updatePosition()" method, defined in the parent class, Mover
    override protected function updatePosition(evtObj:Event):void
    {
      // Include the instructions of the "updatePosition()" method from the base class
      super.updatePosition(evtObj);
      bounceAtBorder();            // calls the "bounceAtBorder()" method, defined above
    }
  }
}
- See the explanations in code.
- Save this class with the name "MoverChild.as" in the same directory as "Mover.as".
- In the FLA document in which the "sfer" MovieClip instance is created, right-click on the Frame 1 in the Timeline and choose "Actions". Delete any existing code in Actions panel, and add the following code:
// Create an instance of MoverChild class
var obj2:MoverChild = new MoverChild(sfer, 2, 3);
obj2.startMove();         // Call the "startMove()" method
- Notice that, even if the "startMove()" method does not exist in the "MoverChild" class, it can be called through this instance of the child class, because it's inherited from the parent class as if it was written in it.
- If you press "Ctrl+Enter", the Flash Player will display a presentation like this.

• In the child class you can also rewrite the properties and methods inherited from the parent class.
In the example above, in the "MoverChild" subclass, the values of the 'xVel' and 'yVel' properties are modified, and the 'updatePosition()' method is rewritten; all defined in the "Mover" parent class.
In the "updatePosition()" from child class we use the "super.updatePosition(evtObj)" expression to include the functionality of this method from parent class, then we added another instruction. In this way we keep the functionality of the original method, and also add new instructions.

To rewrite a method use override keyword in the definition of that method in the child class. With this syntax:
override attribute function methodName() {
  // The code that will replace the original one
}
  - Rewritting a method does not affect the original in the parent class, the modifications are available only in the child class, respectively in its subclasses.
  - To keep using the initial code (from the parent class) in the rewritten function, include it with super.methodName(); in the body of the function in child class.
- "super.methodName()" includes "methodName()" from the parent class.

The super() function calls the constructor method of a parent class, it must contain a number of arguments equal to the number of parameter of the constructor from the parent class. If it's not added in the child class code, it will automatically be added by the program, but without arguments. So, if the constructor of a parent class contains parameters, you must add "super(parameters)" in the constructor of the child subclass.

Creating subclass that extends child class

Sub-classes can also be extended in other child classes, so, the first child class becomes a parent of other subclasses extended from it, these are grandchildren of the original base class.
• The "grandchild" classes can not directly inherit the properties and methods of the "grandparent" class, but they inherit them through the class they are extended from.


To show how to create and use a subclass extended from a child class, we will continue with the example presented until now in this lesson.
The base class "Mover" can move and stop the motion. Its child class, "MoverChild" changes motion direction when the object reached the borders. Now, we will define a child class extended from "MoverChild", named "MoverChildG". In this subclass we add an "effect of gravitation", that will pull the object down and slow it until it stops.
- Because the "MoverChildG" extends "MoverChild" and not directly the base class, it inherits the capacity to not let an object leaves the borders.
Open a new "ActionScript 3.0 Class" document, give it the name "MoverChildG", delete the initial code in it and copy the following code:
// Create the package (without name)
package {
  // Import classes whose properties and methods will be called in this class
  import flash.display.MovieClip;
  import flash.events.Event;
  import MoverChild;           // Import its parent class

  // Start defining the MoverChildG, subclass of the MoverChild class
  public class MoverChildG extends MoverChild
  {
    // Define this classes properties
    // with "private" attribute because they are used only in the code of this class
    private var streng: Number;
    private var lastPosX: Number;
    private var lastPosY: Number;

    // Constructor
    // Besides the attributes necessary for the class from which it is extended, also add a "streng" (for motion power)
    // ('stren' having a default value, makes it optional when it is created an instance of this class)
    public function MoverChildG(inMC:MovieClip, xV:Number, yV:Number, streng:Number=1)
    {
      // Call the Constructor of the parent class (from which it is extended)
      super(inMC, xV, yV);

      // Assign the value of the "streng" parameter to the 'streng' property
      // The same name was given both the property and the parameter to better know it's role (but it can also have a different name)
      this.streng = streng;
    }

    // Rewrite the "updatePosition()" method, defined in the parent class
    override protected function updatePosition(evtObj:Event):void
    {
      // Include /Keep the initial code of this method and adds other instructions too
      super.updatePosition(evtObj);
      this.applyGravity();
      this.applyFriction();
      this.checkForStop();
    }

          /* The internal functions are defined private, because they are only needed inside this class */

    // Increas the speed on the Y axis with the 'streng' property
    private function applyGravity():void
    {
      this.yVel += this.streng;
    }

    // Add the gravitational coeficient G (0.98) to the speed on the X and Y axes 
    // by multiplication, to gradually reduce their value
    private function applyFriction():void
    {
      this.xVel *= 0.98;
      this.yVel *= 0.98;
    }

    // The Function used to verify the moment when motion has stopped
    // calls the "stopMove" method from the base class
    // ("stopMove" deletes the record of the ENTER_FRAME event's detection,
    // not being necessary after stopping, it frees up memory occupied by this event)
    private function checkForStop():void
    {
      // If the X and Y position is the same as the last recorded one
      if(this.insMC.x == this.lastPosX && this.insMC.y == this.lastPosY)
      {
        this.stopMove();          // Calls "stopMove" method
      }

      // Retains in 'lastPosX' and 'lastPosY' properties the last position
      this.lastPosX = this.insMC.x;
      this.lastPosY = this.insMC.y;
    }
  }
}
- Detailed explanations about the instructions used in this class are in the comments in code.
- Save this class with the name "MoverChildG.as" in the same folder as "Mover.as" and "MoverChild.as".
- In the FLA document (from the same folder) where the "sfer" MovieClip instance was created, right-click on the Frame 1 in the Timeline and choose "Actions", delete any existing code in the "Actions panel" and add the following code:
// Create instance of MoverChildG class
var obj3:MoverChildG = new MoverChildG(sfer, 15, 30, 2);
obj3.startMove();         // Call "startMove()" method
- If you press "Ctrl+Enter", the result will be the motion of the object as is shown in the following presentation (click on image).
as3-inheritance_parent_child_class

• From all these examples you can see how efficient is to use the inheritance. New things can be created, without to modify the base class, and without creating again its properties and methods.

You can also create classes that can not be extended. These classes are called "final class".
To create a "final class", add the term final before the keyword class:
For example:
            package {
                public final class ClassName {
                    // Instructions ...
                }
            }


- The FLA and AS files with examples from this lesson can be downloaded from: Inheritance - Parent and Child classes.