Terminology

The class which is inherited (or derived) from is called the:

superclass (Java)

base class (C++)

parent class or ancestor class

The class which inherits is called a:

subclass (Java)

derived class (C++)

child class or descendant class

Note that the terms subclass and superclass can be confusing!

Superclass

Subclasses

Can you understand why?

An Example

Here’s an example involving Employees and Managers.

Employee Class

Consider the class Employee:

package company;

import java.util.Date;

public class Employee
{
    // Constructor
    public Employee(String n, double s, Date d)
    {
        m_name = n;
        m_salary = s;
        m_hireDate = d;
    }

    // Instance methods

    public void raiseSalary(double byPercent)
    {
        m_salary *= 1 + byPercent/100;
    }

    public int getHireYear()
    {
        return m_hireDate.getYear() + 1900;
    }

    public void print()
    {
        System.out.println(m_name + " " +
                           m_salary + " " +
                           getHireYear());
    }

    public String getName()
    {
        return m_name;
    }

    //////////// Private Data //////////////////
    private String	m_name;
    private double	m_salary;
    private Date	m_hireDate;
}

Now, imagine that you want to give all Employees a raise:

package company;

import java.util.Date;

public class EmployeeTest
{
    public static void main(String[] args)
    {
        Employee[] staff = new Employee[3];

        staff[0] = new Employee("Charlie Chaplin",
                                34000,
                                new Date(78, 7, 9));
        staff[1] = new Employee("Florence Nightingale",
                                100,
                                new Date(71, 4, 23));
        staff[2] = new Employee("Mother Theresa",
                                0,
                                new Date(89, 3, 5));
        for (int i = 0; i < staff.length; i++)
            staff[i].raiseSalary(5);     // by 5 percent
        for (int i = 0; i < staff.length; i++)
            staff[i].print();
    }
}

This produces the following output:

Charlie Chaplin 35700.0 1978
Florence Nightingale 105.0 1971
Mother Theresa 0.0 1989

Manager Class

However, you work for a company that gives raises to its managers differently from raises to its regular employees. (Don’t they all?)  Furthermore, managers have access to a secretary and other perks.

As the programmer for this company’s salary application, you naturally decide to use inheritance to model these differences. So you create a class Manager (a subclass of Employee — appropriate?):

package company;

import java.util.Date;

public class Manager extends Employee
{
    public Manager(String n, double s, Date d,
                   String secretaryName)
    {
        super(n, s, d);
        m_secretaryName = secretaryName;
    }

    public void raiseSalary(double byPercent)
    {
        // Add 1/2% bonus for every year of service
        Date today = new Date();
        double bonus =
                0.5 * (today.getYear() + 1900 - getHireYear());
        super.raiseSalary(byPercent + bonus);
    }

    public String getSecretaryName()
    {
        return m_secretaryName;
    }

    public void setSecretaryName(String name)
    {
        m_secretaryName = name;
    }

    //////////// Data //////////////////
    private String	m_secretaryName;
}

Note that the Manager class overrides the raiseSalary(double byPercent) method, which recalculates the percentage raise and then calls its superclass’s (that is, the Employee class’s) raiseSalary method to complete the setting of the raise

The Manager class also adds two secretary-related methods.

Everybody gets a raise!

Now you can give all Employees (including Managers) a raise:

package company;

import java.util.Date;

public class ManagerTest
{
    public static void main(String[] args)
    {
        Employee[] staff = new Employee[3];

        staff[0] = new Employee("Charlie Chaplin",
                                34000,
                                new Date(78, 7, 9));
        staff[1] = new Employee("Florence Nightingale",
                                100,
                                new Date(71, 4, 23));
        staff[2] = new Manager("Mother Theresa",
                                120000,
                                new Date(89, 3, 5),
                                "Demi Moore" // Secretary name
                                );

        for (int i = 0; i < staff.length; i++)
            staff[i].raiseSalary(5);     // by 5 percent

        for (int i = 0; i < staff.length; i++)
            staff[i].print();
    }
}

Note that we can write:

staff[2] = new Manager("Mother Theresa",
                       120000,
                       new Date(89, 3, 5),
                       "Demi Moore" // Secretary name
                       );

even though staff[2] is of type Employee, because we declared the class Manager as extending from Employee — that is, a Manager is a kind of Employee.Question Would the following be legal/valid?

Manager bill = new Employee("Bill Gates",
                            20000000.00,
                            new Date(85, 1, 1));

When the above program is run, it produces the following output:

Charlie Chaplin 35700.0 1978
Florence Nightingale 105.0 1971
Mother Theresa 133800.0 1989

Points to Notice

Here are some points of interest in this example:

  • The keyword extends is used to specify that a class (Manager, in this case) is a subclass of another class (here, Employee), which is the superclass.
  • Class Manager inherits all the data and methods of class Employee
  • Class Manager overrides the raiseSalary() method
    • (Notice the distinction between override and overload.)
  • When we call the raiseSalary()method:
    • The compiler does not know the proper method to invoke at compile time
      • When the method can be determined at compile time, it is called compile-time binding)
    • Instead, the compiler generates code that will dynamically determine the proper method to call at run time
      • When the method is determined at run time, it is called dynamic bindinglate binding, or run-time binding)
  • When we called the print() method, because we did not implement a print() method on Manager class, the dynamic binding code finds only the Employee.print() method, and so calls it.