Inheritance
Why inheritance?
Inheritance is probably the most powerful feature
of object-oriented programming
after classes themselves
New classes can be created via inheritance faster,
easier, and cheaper than writing them from scratch
At the heart of inheritance is the idea of software
reuse.
How inheritance works
A new class,
called a derived class, is created from an existing, or base class.
The derived class inherits all the members from the
base class
It can also add new data members and member functions
The base class is not changed by having classes
derived from it.
Equivalent terminology
Superclass and
subclass
Base class and
derived class
Parent class and
child class
Generalization/specialization
A class can be viewed as a set of objects that have
something in common.
We could then have subsets of the first class.
Each subset has
all the characteristics of the first class, plus some things that are common to
the subset
Example:
all living things.
As we move away from the first set, we are moving from
general characteristics toward more and more specific characteristics
Possible relationships between classes
is-a means one
class is-a type of the other class
An employee is-a
type of person
A book is-a type
of ReadMaterial
All inheritance
should have is-a relationship
has-a means one class has-a part of another class.
A book has-a author.
has-a relationships describe containment. The class Book would contain an instance
variable of type Author.
Here, one class
is used within (or as an instance variable) of another
Example of a base class
class Person
{
protected int ssn;
protected String name;
public Person( int num, String n)
{ ssn = num;
name = n }
public String
getName( ) { return name; }
public int
getSsn( ) { return ssn; }
}
Student class derived from Person
class Student extends Person
{ private double gpa;
private
String major;
public Student( int num, String n,
double grade, String m)
{
super(num, n)
// call the superclasses constructor
gpa
= grade;
major
= m;
}
public double getGpa( )
{ return gpa; }
} // end class student
Accessing Base Class Members
If we create an object of type Student,
and try to access a member function like this:
Student st = new Student(123456789, "Jane", 4.0, CS );
int ssnNum;
ssnNum= st.getSsn( );
The compiler looks first at the derived class for the
function; if it does not find the method there, it looks in the base class for
the function
The protected access specifier
In order for the derived class to directly access the
base classs data, the data must be declared as protected, not private.
This breaks encapsulation; any derived class can
access the data directly
Sometimes base classes do not declare their data
protected,
Instead, they
insist that derived classes use member functions to access and change their
private data
But this is not
usually done.
Constructor chaining
The Student class has four
instance variables:
Two inherited from the Person class, and two of its
own.
The superclasses constructor must initialize its
instance variables
The Java language guarantees
that a constructor is called every time a class instance is created.
If the call to super is omitted, Java inserts a
call to the default superclass constructor
If the programmer doesnt
explicitly call the suprclasses constructor , Java
will implicitly call the superclasses default constructor (no arguments)
Overriding member functions
Suppose we have a base class called square, with a derived rectangle
class.
We want to find the area in both the base and derived
class
But different formulas must be used in the member
functions of each
So the derived class, Rectangle, overrides the base
classs area function.
When a derived class overrides a base class member
function, the signature must be the same.
class Square
{ protected int width;
public Square(int w) {width = w }
public int getWidth( ) { return width;
}
public void setWidth(int s) {
width = w; }
public int area( ) {
return width * width; }
}
class Rectangle extends Square
{
private
int length;
public Rectangle(int s, int len) {super(w); length = len; }
public int area( ) {
return width * length; }
}
How overriding works
When a function
is called by an object, it is compared against the objects classs own
function signatures
The signature is
the function name plus the argument list
If a match is found, that function is invoked
If a match is not found, the signature is compared
against the bases function signatures.
This process is repeated upward until a match is
found.
A match is guaranteed because otherwise the C++ compiler
would give an error.