CS 330 Lecture 40 – Multiple Inheritance
Agenda
- what ?s
- design this
- multiple inheritance
TODO
- The Wasd
utilities.rb
was treating aVector2
instance immutably, which violated the spec. It was been updated. You’ll need to pull down the revised file. (Thanks, Paul!)
Note
We start today with this task:
Design a reusable piece of Java code that allows a class to “listen” for just drag events. When such an event occurs, the class wants to be alerted through its
onDrag(int fromX, int fromY, int startX, int startY)
method.
How would you write this code?
Most of the listeners we use in Java are interface
s. They only announce methods that must be appear in their implementors. They contain no state. For the task above, we must have some state to remember the initial mouse position. We must have some implementation to call onDrag
. Therefore, we cannot use an interface
. We use an abstract class instead.
The cost of this is that we can’t extend our listener if we are extending another class. Java only allows single inheritance. We can workaround this with a local subclass. But one must wonder, what’s the big deal with multiple inheritance? Why does it not appear in many languages? Since some languages do support it, the answer can’t be that we don’t know how to support it. Instead, there are a few reasons that language designers choose not to implement it:
- It introduces ambiguity. Suppose two superclasses both implement method
foo
. When someone sayssub.foo()
, whosefoo
gets called? Likewise, suppose two superclasses both have an instance variable namedx
. When you accessx
in the subclass, whosex
are you accessing? C++ overcomes this issue by requiring you to fully qualify references to ambiguous superclass identifiers. - It complicates object layout in compiled programs. We saw last time that objects are a linear stack of their supertypes in memory. Subclasses pile their instance variables below the superclasses’. Instance variables are really just offsets from the beginning of an object’s memory footprint. When multiple inheritance comes in, the linearity of an object gets thrown out of whack.
- It introduces the dreaded diamond. Suppose two superclasses have a common superclass. When a subclass is constructed, does it get two separate grandparent foundations? Or just one? If just one, which of the two parent classes constructs it? C++ avoids this dreaded diamond through virtual inheritance, which basically shuts off all automatic superclass construction. The subclass must actively invoke the superclass constructors.
Code
cole.rb
/usr/lib/ruby/2.7.0/rubygems/dependency.rb:311:in `to_specs': Could not find 'coderay' (>= 0) among 56 total gem(s) (Gem::MissingSpecError)
Checked in 'GEM_PATH=/.gem/ruby/2.7.0:/var/lib/gems/2.7.0:/usr/lib/ruby/gems/2.7.0:/usr/share/rubygems-integration/2.7.0:/usr/share/rubygems-integration/all:/usr/lib/x86_64-linux-gnu/rubygems-integration/2.7.0:/home/johnch/.gems', execute `gem env` for more information
from /usr/lib/ruby/2.7.0/rubygems/dependency.rb:323:in `to_spec'
from /usr/lib/ruby/2.7.0/rubygems/core_ext/kernel_gem.rb:62:in `gem'
from ./coderay:24:in `'
DraggedListener.java
/usr/lib/ruby/2.7.0/rubygems/dependency.rb:311:in `to_specs': Could not find 'coderay' (>= 0) among 56 total gem(s) (Gem::MissingSpecError)
Checked in 'GEM_PATH=/.gem/ruby/2.7.0:/var/lib/gems/2.7.0:/usr/lib/ruby/gems/2.7.0:/usr/share/rubygems-integration/2.7.0:/usr/share/rubygems-integration/all:/usr/lib/x86_64-linux-gnu/rubygems-integration/2.7.0:/home/johnch/.gems', execute `gem env` for more information
from /usr/lib/ruby/2.7.0/rubygems/dependency.rb:323:in `to_spec'
from /usr/lib/ruby/2.7.0/rubygems/core_ext/kernel_gem.rb:62:in `gem'
from ./coderay:24:in `'
DrawFrame.java
/usr/lib/ruby/2.7.0/rubygems/dependency.rb:311:in `to_specs': Could not find 'coderay' (>= 0) among 56 total gem(s) (Gem::MissingSpecError)
Checked in 'GEM_PATH=/.gem/ruby/2.7.0:/var/lib/gems/2.7.0:/usr/lib/ruby/gems/2.7.0:/usr/share/rubygems-integration/2.7.0:/usr/share/rubygems-integration/all:/usr/lib/x86_64-linux-gnu/rubygems-integration/2.7.0:/home/johnch/.gems', execute `gem env` for more information
from /usr/lib/ruby/2.7.0/rubygems/dependency.rb:323:in `to_spec'
from /usr/lib/ruby/2.7.0/rubygems/core_ext/kernel_gem.rb:62:in `gem'
from ./coderay:24:in `'