OOP Class Notes for 09/24/13
Overview of Inheritance, Method Overriding and Virtual Method Dispatch
- Why Use Inheritance?
- Inheritance in Java
- Inheritance in C++
- Static Typing, Dynamic Typing and Virtual Method Dispatch
Overall, inheritance enables modularity (separate classes), code reuse (inhertiance itself), and selective extensibility (method overriding).
Why Use Inheritance?
-
Bad ways to create a Color Point
- Modifying the existing code for the point class
- This means all instances of a Point must have a Color
- Less flexible and wastes space if we don't need Color in an implementation
- Doing this over and over will make the Point class very complex, making it harder to read and more likely to introduce bugs with each modification
- Copy the entire code and create a new class with it that contains both point and color as fields
- Extra work to rewrite all of the methods of Point to correspond to a Color Point
- Writing the same code that was written before
- Might copy bugs, which will take twice as long to squash
- Note : Copying and pasting isn't necessarily bad, especially while getting code up and running, just use it as a tool to work toward good code, not as a final solution.
- Modifying the existing code for the point class
- Better way to do it - Inheritance
- Color Point (the subclass) inherits from Point (the superclass)
- Subclass inherits all of the superclass's behavior and structures, i.e. methods and data
- This is called the "is a" relationship - e.g. every Color Point is a Point, but not vice versa
- The subclass is guaranteed to have all of the properties of the superclass in addition to newer, more specific properties
- This concept is called (subtype) polymorphism. Use inheritance to save coding effort.
- For the following sections, refer to
Point.java
from the 2nd lecture for the source code for the JavaPoint
and the code from today's lecture for the source code for the C++Point
,Color
,ColorPoint
andmain
Inheritance in Java
java.lang.Object
is a static supertype you can use anywhere- It is the root of the class hierarchy in Java
- It is implicit that every class inherits it. There is no need to write
extends Object
. - Every class in Java inherits and implements
Object
's methods implicitly (there is no data)- For the translator project we only have to implement the following:
String toString() int hashCode() boolean equals(Object o) Class getClass()
- For the translator project we only have to implement the following:
- The is a relationship describes the relationship between classes and superclasses - every
Point
is anObject
Object
is more generic thanPoint
- You can use a
Point
anywhere anObject
is specified but not vice versa
- Take a look at how we can use a
Point
public static void main(String[] args) { Object o = new Point(0, 1, 2, 3); String str = o.toString(); String str = new Object().toString(); int dist1 = o.getDistanceFrom(Point.ORIGIN); int dist2 = ((Point) o).getDistanceFrom(Point.ORIGIN); }
Object o = p1;
legal?
- Everywhere there is an
Object
aPoint
may appear - Statically, assigning a variable of type
Point
but in practicality it is different
o.toString()
legal java code?
- Yes!
o
is statically declared to be anObject
- Compiler knows this must be an
Object
and have all ofObject
's methods - This will use
Point
'stoString()
method becausePoint
overwrites thetoString()
method inObject
, i.e. it is the most specific version oftoString()
available
o.getDistanceFrom(Point.ORIGIN)
legal?
- No, there is no way to know you are always referencing a
Point
- you can't use something more generic than required- You can solve this by explicitly casting a type like the last line in the example above:
(Point) o
- You can solve this by explicitly casting a type like the last line in the example above:
- A method accepting an
Object
argument may be called with anyObject
, including aPoint
new
Object().toString()
you would just get the
the name of the object's Java class and the object's hash code ("java.lang.Object@38503429
")class Point extends Object
Inheritance in C++
Object
in C++
- Inheritance is defined explicitly
- C++ distinguishes between initializing a value and assigning one. Assignments may make copies initializers don't.
- The is a relationship - every
ColorPoint
is aPoint
Color
.h, which defines a color object
class Color { unsigned char r, g, b; ... Color(unsigned char r, unsigned char g, unsigned char b)
: r(r), g(g), b(b) {} unsigned char red() const {
return r;
} ... };
: r(r), g(g), b(b)
is an intializer list- The first
r
inr(r)
refers to the fieldr
in the scope of the class. - The second
r
inr(r)
refers to the valuer
in the scope of the constructor. - These values are initialized in the order in which they are
declared within the class.
- In
Color
, the initialization order isr
,g
,b
because they are declaredunsigned char r, g, b
, not because of the order they appear in the initializer list.
- In
- Only with the C++ standard C++11 do initializer lists support initialization of arrays. If your compiler does not support C++11 then you must initialize arrays in the body of the constructor.
- Using initializer lists is considered good style in C++.
- We specify
unsigned char
because whether char is signed/unsigned is implementation specific; we have decided to be explicit about it in our code. - The getters for the RGB values are inlined into this header file as well.
- Question : What is right to inline?
- Trivial actions like returning
- Initialization of variables
- Some basic operations
- Question : What is right to inline?
- They are
const
because we are not modifying the actual data
Point.h
, where we define a Point
and a ColorPoint
- A
ColorPoint
can appear everywhere a Point can appear. - Every
ColorPoint
is aPoint
, so we will want to re-write (i.e. override) the methodtoString()
- We use the keyword
virtual
in front of the method declaration in thePoint
class to let the compiler know we want to be able to automatically override a methodvirtual string toString() const;
- Once a method is declared
virtual
, it is automatically a virtual method in all of its subclasses and does not need to be specified asvirtual
again in order to be overridden - C++ syntax for inheritance is
class ColorPoint : public Point
(the superclass must be public)
Static Typing, Dynamic Typing and Virtual Method Dispatch
- For variables
p
that point to an object, we distinguish betweenp
static and dynamic types.- Static type: the type of
p
known to the compiler at compile time, i.e., from the declaration ofp
. - Dynamic type: the actual type
of
p
at runtime determined by the object to whichp
points.- Without inheritance, static and dynamic types are the same
- With inheritance, the dynamic type is the type of the object the variable was last changed to.
- Virtual Method Dispatch
- In C++, methods are called based on the dynamic type only if they are virtual; otherwise they are called based on the static type
- All Java methods are virtual, except private methods, because you can't see them, and static methods, because they don't have an associated instance
- In other words, all Java public and protected instance methods are virtual; you can override them in a subclass to specialize the behavior of a static type
- Virtual methods in Java and C++ look for the most specific implementation of a method, i.e. the one furthest down the inheritance chain
- Translating these types of Java methods to C++ code that does not use virtual methods is the CORE OF THE PROJECT.
- Virtual method dispatch only works in C++ with pointers and references
- C++ pointers and virtual method dispatch
Point* p = new ColorPoint(Color::WHITE, 0, 1, 2, 3); p->toString(); ColorPoint* cp = new ColorPoint(Color::RED, 0, 1, 2, 3); cp->toString(); Point::ORIGIN.getDistanceFrom(*cp)
- The
new
operator allocates memory for the object on the heap (like in Java) rather than inline (which Java cannot do) - The dynamic type of both
p
andcp
is aColorPoint*
(a pointer to aColorPoint
) - The static type for
p
is aPoint*
and the static type forcp
is aColorPoint*
- Since
cp
is aColorPoint*
,cp->toString()
will callcp
'stoString()
no matter what p
will also callColorPoint
'stoString()
based on our implementation (the method is declared asvirtual
andp
's dynamic type isColorPoint*
)- If we did not make it a virtual method
p->toString()
would callPoint
'stoString()
based on its static type
- If we did not make it a virtual method
- If you look at
Point::ORIGIN.getDistanceFrom(*cp)
you will see that, like Java, you can use aColorPoint
where aPoint
is expected because aPoint
is more generic - Remember, for C++, you have to use arrow notation for pointers to objects, i.e
p->toString()
- Static type: the type of