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.javafrom the 2nd lecture for the source code for the JavaPointand the code from today's lecture for the source code for the C++Point,Color,ColorPointandmain
Inheritance in Java
java.lang.Objectis 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
Pointis anObjectObjectis more generic thanPoint- You can use a
Pointanywhere anObjectis 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
ObjectaPointmay appear - Statically, assigning a variable of type
Pointbut in practicality it is different
o.toString() legal java code?
- Yes!
ois statically declared to be anObject - Compiler knows this must be an
Objectand have all ofObject's methods - This will use
Point'stoString()method becausePointoverwrites 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
Objectargument 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 ObjectInheritance 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
ColorPointis 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
rinr(r)refers to the fieldrin the scope of the class. - The second
rinr(r)refers to the valuerin 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,bbecause 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 charbecause 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
constbecause we are not modifying the actual data
Point.h, where we define a Point and a ColorPoint- A
ColorPointcan appear everywhere a Point can appear. - Every
ColorPointis aPoint, so we will want to re-write (i.e. override) the methodtoString() - We use the keyword
virtualin front of the method declaration in thePointclass 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 asvirtualagain 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
pthat point to an object, we distinguish betweenpstatic and dynamic types.- Static type: the type of
pknown to the compiler at compile time, i.e., from the declaration ofp. - Dynamic type: the actual type
of
pat runtime determined by the object to whichppoints.- 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
newoperator allocates memory for the object on the heap (like in Java) rather than inline (which Java cannot do) - The dynamic type of both
pandcpis aColorPoint*(a pointer to aColorPoint) - The static type for
pis aPoint*and the static type forcpis aColorPoint* - Since
cpis aColorPoint*,cp->toString()will callcp'stoString()no matter what pwill also callColorPoint'stoString()based on our implementation (the method is declared asvirtualandp'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 aColorPointwhere aPointis expected because aPointis more generic - Remember, for C++, you have to use arrow notation for pointers to objects, i.e
p->toString()
- Static type: the type of