Lecture 14 Multiple Inheritance
Multiple Inheritance
• Inheritance is a powerful concept
CS 600.120 Intermediate Programming
– derived class inherits properties of the parent
Multiple Inheritance Compared – polymorphic invocation of functions
– collection of heterogeneous objects
• C++ supports multiple inheritance
• So, twice the inheritance should be twice as powerful
– properties of multiple classes
– complexity when poorly used – polymorphic functions and properties from multiple classes
– added complexity, particularly when inheriting data members
• Java restricts multiple inheritance
from multiple classes
– provides an interface abstraction, which is a abstract base class
with no data members CS 600.120 Intermediate Programming
– a derived class can inherit from only a single base class Multiple Base Classes (C++)
– but, can provide multiple interfaces
– interfaces can be used to construct heterogeneous collections • Syntax
CS 600.120 Intermediate Programming – specify multiple classes from which to inherit
The TextBox Object (C++) • Semantics
• Is an instance of both Shape and string classes – inherits all the properties of all classes
– can be truncated to either class TextBox : public Shape, public string
– can be pointed to by pointers of either base class {
string * stp = new TextBox ( p, “Box1” ); public:
Shape * shp = new TextBox ( p, “Box2” ); Text ( Point, String );
string st ( *stp ); // invokes string::string ( string & ); void move ( int x, int y );
void scale ( Point p, double s );
// truncated to string void plot ( Graphics& g ) const;
Shape sh ( *shp ); // invokes Shape::Shape ( Shape & );
private:
// truncated to Shape Point _start;
CS 600.120 Intermediate Programming }
CS 600.120 Intermediate Programming
Object Layout (C++)
• Memory view class TextBox
Shape
• Can TextBox be both a Shape and a string
String
– not in the traditional inheritance sense
– shape and string are not totally orthogonal
– consider aggregating the strings of two
TextBoxs at different locations
– What is the proper behavior?
TextBox
CS 600.120 Intermediate Programming
1
Repeated Base Classes (C++) Repeated Base Classes (C++)
• It is illegal to inherit from the same base class twice • But, it is possible to have the same base class twice
– for no good reason – in more complex hierarchies
– imagine a point in a 2-dimensional cartesian space
– not that this gives you the behavior that you want class StopSign : public Polygon, public TextBox
– What’s wrong with it? {
class TwoDCartesianPoint : public Point, public Point ...
{ }
... StopSign
}
TextBox Polygon
CS 600.120 Intermediate Programming
string Shape
CS 600.120 Intermediate Programming
Repeated Base Classes (C++) Shared Base Classes (C++)
• But, it is possible to have the same base class twice • In some cases, the same class is inherited twice, but
represents a single instance of the class
– in more complex hierarchies
– in this case, it is desirable to eliminate two copies
• Calls to methods of the re-occurring base class are
ambiguous • Teaching assistant class
– C++ provides techniques to disambiguate calls – represents one person Person
– but, that doesn’t make the design reasonable – is a student
– is an employee
Student Employee
StopSign s; // refers to which Shape::move()?
...
s.move();
BadStudent TA
CS 600.120 Intermediate Programming CS 600.120 Intermediate Programming
Shared Base Classes (C++) Virtual Inheritance (C++)
• Two instances of Person represents a problem • C++ provides a technique to factor out copies
– wastes space – called virtual inheritance
– have to use a single copy or keep both copies consistent
– burden on the programmer • Virtual is not very descriptive
CS 600.120 Intermediate Programming – not related (or similar) to virtual functions
– named virtual because a similar indirection mechanism is used in
resolving scope
• Does not solve our StopSign problem
• Requires foresight by the implementor of intermediate
classes
class Student : virtual public Person
class Employee : virtual public Person
class TA : public Student, public Employee
CS 600.120 Intermediate Programming
2
A Virtual Inheritance Observation Construction (C++)
• As a hypothetical • Constructors for multiple inheritance are simple
– imagine that Java supported multiple inheritance – construct all of the base classes
– all classes in Java inherit from class Object – do so in the initialization phase
– thus, with multiple inheritance, all objects that inherit from
class StopSign ( Point p, string t )
multiple classes, would share object : TextBox ( p, t ),
– it follows that any classes used in multiple inheritance would need Polygon ( 9 )
to be virtual to share Object {
– which would prevent repeated base classes, which we needed for for ( int i=0; i < 9; i++ )
{
StopSign // initialize the vertices
}
• Whew!
}
CS 600.120 Intermediate Programming
CS 600.120 Intermediate Programming
Construction for Virtual Inheritance (C++) Construction for Virtual Inheritance (C++)
• Need some mechanism to ensure that the class is only • Specific constructor can be invoked in the most-derived
constructed once class
– invoking two constructors could overwrite data and lead to – no further derivation from this class
unpredictable results – requires planning ahead again
• Preferred option • TA invokes Person
– provide a default constructor for the shared base class and let the – even though it is not derived from person
compiler invoke it
TA::TA ( string name, double salary )
– cannot be invoked explicitly by any of the intermediate classes : Employee ( salary ),
Person ( name )
• Specific constructor can be invoked in the most-derived
class {
}
– no further derivation from this class
– requires planning ahead again CS 600.120 Intermediate Programming
CS 600.120 Intermediate Programming
Ambiguity Resolution (C++) Ambiguity Resolution (C++)
• Repeated feature names • Name collisions of unrelated functions
– are ambiguous and cannot be resolved by compiler – cannot be merged because they are fundamentally different
– are a compile-time error – generally when people name functions bad things like test()
StopSign s {...}; // is either Polygon::plot() class TextBox : public Shape, public String
S.plot(g); // or TextBox::plot() {
• Merging features public:
virtual boolean test(); // returns string == “”
– names in multiple base classes should be defined in derived class
– can invoke both features by scoping }
void StopSign::plot ( Graphics& g ) const class Polygon : public Shape
{ {
Polygon::plot ( g ); public:
TextBox::plot ( g ); virtual boolean test(); // returns 0 for uninitialized vertices
}
}
class StopSign : public TextBox, public Polygon
{
public:
boolean test(); // implemented to invoke TextBox::test
}
CS 600.120 Intermediate Programming CS 600.120 Intermediate Programming
3
Ambiguity Resolution (C++) Renaming Classes (C++)
• Seems like no problem, Polygon::test() can be invoked • Polymorphic hierarchy can be preserved through renaming
explicitly
– disambiguates the call to test()
• But, this destroys the polymorphic hierarchy
class PolygonRenamer : public Shape
– if we have pointers to Shapes, what test gets invoked? {
Shape * s = new StopSign ( p, s, n ); public:
virtual boolean test () const { poly_test (); }
... virtual boolean poly_test () = 0;
}
s->test(); // What gets invoked?
class Polygon : PolygonRenamer
{
virtual boolean poly_test ();
}
class StopSign : class Polygon, class TextBox
{
virtual boolean test (); // calls TextBox::test();
virtual poly_test (); // makes poly_test() available
}
CS 600.120 Intermediate Programming CS 600.120 Intermediate Programming
Renaming Classes (C++) Ambiguity in Repeated Bases (C++)
• Note that class Polygon still has a member function test() • If repeated bases appear in an inheritance hierarchy,
inherited from the PolygonRenamer pointers to the repeated base are ambiguous
– Polygon still provides the same interface and old code will still – cannot determine which of the two classes is intended
compile and run the same way
list < Shape * > figure;
– Polygon::test() resolves to PolygonRenamer::test(), which figure.push_back ( new StopSign (...)); // Ambiguous
polymorphically calls Polygon::poly_test()
CS 600.120 Intermediate Programming
class PolygonRenamer : public Shape
{
public:
virtual boolean test () const { poly_test (); }
virtual boolean poly_test () = 0;
}
class Polygon : PolygonRenamer
{
virtual boolean poly_test ();
}
CS 600.120 Intermediate Programming
Multiple Inheritance Redux (C++) Multiple Inheritance (Java)
• Multiple inheritance adds complexity • Java classes inherit from a single base class
– confusing ambiguity rules – design decision based on experiences with C++
– awkward constructs to resolve them – disadvantages of complex layout and ambiguity outweigh scoping
• Multiple inheritance works well in limited cases rules
– if base class branches are totally disjoint • However, it is useful to be able to put objects in multiple
– for hard to model relationships heterogeneous collections
• Conceptually correct multiple inheritance is rare – let’s consider a Web server architecture
• Use this feature rarely and only with good reason CS 600.120 Intermediate Programming
CS 600.120 Intermediate Programming
4
Abstract Web Server Architecture Abstract Web Server Architecture
Object • Every specialized server “is a” server
Runnable Server – classic inheritance
HTTPServer ........... FTPServer SecureServer • Every server needs to be a thread
HTTPSServer – so that we can invoke operations like start and stop
CS 600.120 Intermediate Programming • Multiple heterogeneous collections
– as servers
– as threads
• Check out HTTPSServer
– is a server, is a secure server, is runnable, ..., uh oh
• For many of these, we don’t need the base state just:
– interface, for uniformity
– ability to create heterogeneous collections
CS 600.120 Intermediate Programming
Abstract Web Server Architecture Interfaces
• The code below is how we would like it to run • Interfaces are abstract base classes that have no data
• This would seem to demand that: members
– java support multiple inheritance – different from abstract classes
– java support virtual inheritance (because all objects are derived
abstract class Server
from java.lang.object) {
• But, we know that java only supports single inheritance public void init ();
public void start ();
Server s[NumSErvers]; public int status ();
s[0] = new HTTPServer ( ... ); public void logEvent ( DataOutputSteam ds );
s[1] = new FTPServer ( ... );
... int status;
s[k] = new HTTPSServer ( ... ); }
for ( int i = 0; i < NumServers; i++ ) interface SecureServer
{
{
public void bind ( SSLAuth auth );
s[i].init(); // invoke Server.init() polymorphically public encrypt ( buffer );
public void decrypt ( buffer );
s[i].run(); // invokes Runnable.run() polymorphically }
} CS 600.120 Intermediate Programming
CS 600.120 Intermediate Programming
Interfaces (2) Interfaces (3)
• Classes may “implement” many interfaces • Interfaces may be used as the “base” class for
heterogeneous collections
– must define all functions from interfaces that one implements
– yeah, that’s what implement means Server[] s = new Server[3] ;
s[0] = new FTPServer (...);
class HTTPSServer extends HTTPServer implements SecureServer, s[1] = new HTTPServer (...);
s[2] = new HTTPSServer (...);
Runnable
Runnable[] r = new Runnable[3];
{ r[0] = (Runnable) s[0];
r[1] = (Runnable) s[1];
/* SecureServer’s interface */ r[2] = (Runnable) s[2];
public void bind ( SSLAuth auth ) {...} Thread[] t = new Thread[3];
for ( int i=0; i<3; i++ )
public encrypt ( buffer ) {...} {
public void decrypt ( buffer ) {...} s[i].init();
t[i] = new Thread ( r[i] );
/* Runnable’s interface */ { HTTPSEntryPoint (); } t[i].start();
public void run () }
/* HTTPSServer’s specific task */ CS 600.120 Intermediate Programming
void HTTPSEntryPoint () {...}
}
CS 600.120 Intermediate Programming
5
Cloneable (Java) Callbacks with Interfaces (Java)
• Cloneable is a common interface • Common use of interfaces is to get handle system events
– has no data and no functions – often in GUI applications
– Object.clone provides a bitwise object copy
– any class for which this works, can implement Cloneable or • We will use clickable as our example
classes may provide a custom clone(), which is part of object, not – when a click event happens, call object.clicked()
cloneable
interface Clickable
interface Cloneable {} // defined in java.lang {
class Object // defined in java.lang public void clicked ( Button b );
}
{ class ButtonPanel extends Panel
{
Object clone()
public void register ( Clickable obj )
{ {
if (!this instanceof Cloneable ) _registered.addElement ( obj );
}
throw new CloneNotSupportedException() ...
}
.... CS 600.120 Intermediate Programming
} Callbacks with Interfaces (Java)
class HTTPServer : extends Server implements Runnable, Cloneable • Every class that registers with ButtonPanel gets told:
{ ... }
– when an clicked event occurs
CS 600.120 Intermediate Programming – to what button the event occured
Callbacks with Interfaces (Java) • A lot of Java source ends up looking like this
class ButtonPanel extends Panel class SaveDialog implements Clickable
{ {
public void register ( Clickable obj ) public void clicked ( Button b )
{ {
_registered.addElement ( obj ); if ( b.getLabel () == “Cancel” )
} return;
public void Action ( Event evt, Object arg ) else if ( b.getLabel() == “OK” )
{ app.save();
if ( evt.target instanceof Button ) else ...
{ }
WindowApp app;
Button button = (Button) evt.target; }
for ( int i = 0; i < _registered.size(); i++ ) CS 600.120 Intermediate Programming
{
Function Pointers
Clickable obj = (Clickable) _registered.elementAt ( i ).
obj.clicked ( button ); • Can construct a pointer or reference to any feature in C++
}
} – includes functions and member functions
else ...
} • Function pointers
...
private Vector _registered; – variable that “points” to a function
} – used to dynamically bind functions in programs
CS 600.120 Intermediate Programming • functions calls are statically bound, by compiler
• function pointer variable may “point” to different functions at runtime
Callbacks with Interfaces (Java)
CS 600.120 Intermediate Programming
• Every class that registers with ButtonPanel gets told:
6
– when an clicked event occurs
– to what button the event occured
• A lot of Java source ends up looking like this
class SaveDialog implements Clickable
{
public void clicked ( Button b )
{
if ( b.getLabel () == “Cancel” )
return;
else if ( b.getLabel() == “OK” )
app.save();
else ...
}
WindowApp app;
}
CS 600.120 Intermediate Programming
Function Pointer Example Simplifying the Syntax
• Function pointers are variables • Function pointer syntax is awkward
– fp in this case – because variable name is embedded in declaration
• Address of a function name returns pointer to that function • Programmer’s commonly used typedef to improve
readability
– as with any other feature
– lose information that the variable points to a function
• Functions and variables can’t have the same name – looks like it points to a built-in type or object
– they are both features
int print ( char* ); // declaration of a function typedef int ( * FPT ) ( char * ); // Creates type FPT
int (* fp)(char*) = &print; // pointer to function print int print ( char * ); // declaration of print
FPT fp = & print; // looks like a variable
CS 600.120 Intermediate Programming CS 600.120 Intermediate Programming
Invoking Functions by Pointer Matching Function Pointer Prototypes
• Dereference the variable • Function pointer must match the entire prototype
– and give it arguments – strongly typed, helps prevent runtime errors
typedef void ( * FPT ) ( char * ); void (*pf)(char*); // variable pf, pointer to function
int print ( char * arg_str )
{ void f1 ( char* );
int f2 ( char* );
cout << “arg_str” << endl; void f3 ( int* );
}
FPT fp = & print; pf = &f1; // OK matching prototype
*fp ( “Function pointer test” ); pf = &f2; // error - bad return type
pf = &f3; // error - bad argument type
CS 600.120 Intermediate Programming
*pf ( “test string” ); // OK
*pf ( 1 ); // error - bad argument
int i = *pf ( “test” ); // error - type mismatch on return
CS 600.120 Intermediate Programming
Matching Function Pointer Prototypes Matching Function Pointer Prototypes
• Using function pointers to register callbacks • Using function pointers to register callbacks
typedef void ( * fpCallback ) ( void ); class Form // saves form contents to file
class Button { // clears the forms contents
{ // load the saved form
public:
public: Form();
void register ( fpCallback ) void saveForm();
{ void resetForm();
cb_fun = fpCallback; void loadForm();
}
void click () private:
{ Button save;
*cb_fun (); Button reset;
} Button load;
private: }
fpCallBack cb_fun;
Form::Form ()
} {
CS 600.120 Intermediate Programming save.register ( &saveForm );
reset.register ( &resetForm );
load.register ( &loadForm );
}
CS 600.120 Intermediate Programming
7
Living w/out Function Pointers (Java) Collections.sort() and the Comparator Interface
• Use objects instead class WebpageComparator implements Comparator
{
– objects have both data and function
– object variables make function variables public int compare ( Object o1, Object o2 )
{
• Example: the sort method in Collections
WebPage w1 = ( Webpage ) o1;
CS 600.120 Intermediate Programming WebPage w2 = ( Webpage ) o2;
return w1.getHitCount() > w2.getHitCount();
Life w/out Function Pointers }
public int equals ( Object o1, Object o2 )
• Using object variables instead of function pointers {
– easier syntax, more readable ...
}
• Relies on Java interfaces }
– guarantee that the dynamic object provides the needed function List webPgList = new ArrayList();
• Can do similar things in C++ ... // Initialize
– create a class hierarchy Collections.sort ( webPgList, new WebpageComparator );
– register members of the base class
– polymorphically invoke derived class CS 600.120 Intermediate Programming
CS 600.120 Intermediate Programming
8