Title: Inheritance so far
1- Inheritance so far
- base class means the same as superclass
- derived class means the same as subclass
- subclasses inherit behaviour from superclasses
- subclasses can over-ride methods in superclasses
- dynamic binding finds the appropriate method
- dynamic binding only used for pointers or
references - dynamic binding is slower than static binding
(by a bit) - dynamic binding only used for virtual functions
- often the base class doesnt know about derived
classes - this is a good thing (with apologies to Martha
Stewart)
2Abstract Base Classes Suppose we want to write a
program to draw lines, squares or ellipses on the
screen. At run-time the user can choose which
objects to draw. We want the program to keep a
list of the objects that have been drawn so that
the picture can be re-drawn at any time. One
way to proceed would be to declare three classes
Line, Square and Ellipse. However, there is a
certain amount of redundancy in doing this.
3- All three classes will have private data members
that represent the position (say the centre) of
the object on the screen. - They will all have accessors and mutators
associated with these data members. - Object differ from each other in the way they are
drawn. - A disadvantage is that it becomes difficult to
maintain a list of the objects that have been
drawn - such a list would have to be heterogeneous
- it cannot be an array because the types are not
the same - how do we implement such a thing?
- we can use an array of pointers
- all pointers have the same size, but different
types
4A different approach is to realize that a line,
square and ellipse are all examples of a
geometric shape. A single geometric shape class
can contain a data member that specifies what
kind of shape is being drawn. The draw method
contains a switch statement that draws the
relevant shape on the screen. enum shapeType
LINE, SQUARE, ELLIPSE class GeometricShapepu
blic GeometricShape( int x 0, int y 0,
shapeType object LINE ) void draw( void
) const // other member functions
omitted private int xCoord int
yCoord shapeType shape
5The disadvantage to this approach is that if we
want to allow the user to draw a rhombus, we have
to edit the GeometricShape class to allow for the
new shape In particular, we have to add a new
identifier to the shapeType enumerated data
type and we have to add a new case to the switch
statement in the draw method. Hence our code is
not easily extensible.
6Another disadvantage of this approach is that all
objects must have the same fixed size when
displayed on the screen. If we want to be able to
specify the size of an object there is no elegant
way to do it. The problem is that the way we
specify the size of a line or square (by
specifying the length of each line segment) is
not the same way that we specify the size of an
ellipse (by specifying the length of the
semi-major and semi-minor axes). One approach is
to allow for a default parameter void
setSize( int dimen1, int dimen2 0 ) but what
if I want to draw a triangle with sides of
different lengths?
7- An advantage to this approach is that it is easy
to convert a line to an ellipse assuming that we
have a mutator that allows us to change the shape
of an object of type GeometricShape. - GeometricShape myShape( 0, 0, LINE
)myShape.draw()myShape.setShape( ELLIPSE
)myShape.draw() // but what will the
size be? - Another advantage to this approach is that it is
now easy to maintain a list of objects - they are all of type GeometricShape
- hence the list is homogeneous (we could use an
array or linked list)
8A better approach is to realize that a line,
square and ellipse are all special cases of a
geometric shape having a centre. Having made
this observation, we can envision the following
inheritance hierarchy
Now we can maintain a list of objects that have
been drawn by creating a list of pointers to the
base class. We expect that each of the classes
Line, Square and Ellipse will have a draw method
and that this method will override a draw method
in the GeometricShape base class. However, we
cannot implement this method in the base class
because we dont know how to draw an object of
type GeometricShape we dont know its shape!
9We could get around this problem by defining draw
in the base class so it throws an exception if it
ever gets called. Declaration of the
GeometricShape class class GeometricShapepubli
c GeometricShape( int x 0, int y 0 )
void setCentre( int x, int y ) int
getX( void ) const int getY( void ) const
virtual void draw( void )
throw(logic_error(cant Draw base class))
private int xCoord int yCoord
10But we get around this problem by declaring draw
to be a pure virtual function in the base class.
Such functions are not implemented in the base
class. Declaration of the GeometricShape
class class GeometricShapepublic
GeometricShape( int x 0, int y 0 )
void setCentre( int x, int y ) int getX(
void ) const int getY( void ) const
virtual void draw( void ) const 0private
int xCoord int yCoord
11Any class that contains a pure virtual function
is called an abstract base class. It is not
possible to create an instance of an abstract
class because at least one of the member
functions is not implemented. An abstract class
cannot be used as a value type parameter for the
same reason. Any class that is derived from an
abstract base class must override and implement
all pure virtual functions otherwise it also
becomes an abstract class. Note Although we
cannot create instances of an abstract base
class, we can have references and pointers to
such objects! So we can have an array of pointers
to objects in the abstract base class, but each
pointer needs to point to a real subclass
object.
12The declaration of the Line class now looks as
follows class Line public GeometricShapepubl
ic Line( int x 0, int y 0, int length
1 ) void draw( void ) const void
setSize( int length ) int getSize( void )
constprivate int size Note that we
now have a more elegant way of dealing with the
problem of specifying the size of the shape we
can add the relevant number of data members to
the derived class along with associated accessors
and mutators
13The declaration of the Ellipse class now looks as
follows class Ellipse public
GeometricShapepublic Ellipse( int x 0,
int y 0 int sMajor 1, int sMinor 1 )
void draw( void ) const void setSize(
int sMajor, int sMinor ) int getSMajor( void
) const int getSMinor( void )
constprivate int semiMajor int
semiMinor Lets now consider how a client
would use our inheritance hierarchy
14We will store the items to be drawn in an array
of pointers to GeometricShape objects GeometricSh
ape shapeList MAXSHAPES shapeList0 new
Line( 4, 4, 10 )shapeList1 new Ellipse( 0,
-1, 6, 2 )shapeList2 new Square( 0, 0, 5
)drawShapes( shapeList, 3 ) void
drawShapes( GeometricShape shapeList, int num
) for( int index 0 index lt num index
) shapeList index -gtdraw()
15The advantage of this approach is that it is easy
to add new shapes to the inheritance
hierarchy. If we now want to add a rhombus, we
simply create a new class that has GeometricClass
as its base class. There is no need for us to
recompile any of the code that already exists in
the inheritance hierarchy and, if the client code
is well designed, few changes will have to be
made to accommodate the new shape. Our drawShapes
function, for example, will not have to be
changed at all, neither will the data structure
that is used to store the shapes.
16One disadvantage of this approach is that it is
not as easy to convert a shape from one type to
another. If we want to convert a line to a
square, we have to supply a convert
constructor Square( const Line aLine
) In order to be able to convert every object
to every other type of object in the inheritance
hierarchy requires N2 N convert constructors,
where N is the number of classes.
17In the examples we have seen so far, the
inheritance hierarchy has been shallow in other
words, we have had a base class and one level of
derived classes. In practice, it is possible for
the depth of the inheritance hierarchy to be
quite significant. Examples of this include the
Microsoft Foundation Classes (MFC) used to design
Windows programs and the SWING library used to
design graphical user interfaces in JAVA. C
also supports the notion of multiple inheritance
where a class is derived from more than one base
class. We will not be investigating this concept
here.
18Private Inheritance So far we have examined only
public inheritance all the public member
functions of the base class are inherited as
public member functions of the derived class so
that they can be accessed by a client of the
derived class. There is also private inheritance
where the public members of the base class become
private members of the derived class and hence
they cannot be accessed by a client of the
derived class. Private inheritance is not used to
implement is-a relationships. We use private
inheritance when a base class is being used to
implement the derived class but the derived class
has a different public interface than the base
class. class B private A
19Protected Members We have already seen the public
and private access control keywords. There is a
third keyword in this category protected When a
data member or member variable is declared to be
protected, it is not accessible to a client of
the class but a publicly derived class does have
access to that member. class base public p
rotected private
publicly derived class member functions and
friends of derived
base class member functions and friends of base
clients
20Protected Members We have already seen the public
and private access control keywords. There is a
third keyword in this category protected When a
data member or member variable is declared to be
protected, it is not accessible to a client of
the class but a publicly derived class does have
access to that member. class base public
Yes protected No private
No
publicly derived class member functions and
friends of derived
base class member functions and friends of base
clients
21Protected Members We have already seen the public
and private access control keywords. There is a
third keyword in this category protected When a
data member or member variable is declared to be
protected, it is not accessible to a client of
the class but a publicly derived class does have
access to that member. class base public
Yes Yes protected No
Yes private No No
publicly derived class member functions and
friends of derived
base class member functions and friends of base
clients
22Protected Members We have already seen the public
and private access control keywords. There is a
third keyword in this category protected When a
data member or member variable is declared to be
protected, it is not accessible to a client of
the class but a publicly derived class does have
access to that member. class base public
Yes Yes Yes protected
No Yes Yes private
No No Yes
publicly derived class member functions and
friends of derived
base class member functions and friends of base
clients
23Public / Protected / Private inheritance The
public/protected/private attributes in the base
class are determine by the author of the base
class. The author of the derived class can
further restrict access to the base class members
by specifying class derived public base //
access according to base class specs class
derived protected base // access at most
protected class derived private base //
no access to base class members