Object-oriented programming is built on the following.
Here are some historically significant object-oriented languages.
Abstract data types are user-defined data structures along with user-defined operations on these data structures. ADTs hide implementation and representation from the clients, thus the implementation and representation may be changed with out affecting the clients.
ADTs are called classes in object-oriented languages.
Interface:
class Stack[T] {
push(item:T):void
pop():T
top():T
size():int
}
Client Code:
s:Stack[int] := new Stack[int]; s.push(3); s.push(5); print(s.pop());
An Implementation:
class Stack[T] {
private:
items: array[10] of T;
top: int = 0;
public:
push(item:T):void {
items[top] := item; top := top+1; }
pop():T {
top := top-1; return items[top]; }
size():int { return top; }
}
A Better Implementation:
class Stack[T] {
private:
items:list[T] := nil;
public:
push(item:T):void { items.add_first(item); }
pop():T { return items.remove_first(); }
size():int { return items.length(); }
}
Inheritance allows for the definition of a new class as an incremental modification of an existing class.
The new class is called a subclass of the original class (which is called a superclass of the new class).
Subclass gets the instance variables and methods of the superclass.
class Rectangle {
private:
center: Point;
height, width: int;
public:
area():int { return height * width; }
draw(screen:OutputDevice):void { . . . }
move(center2:Point):void { center := center2; }
. . .
}
class ColoredRectangle subclasses Rectangle {
private:
color: Color;
// center, height, width inherited
public:
// area, move inherited
draw(screen:OutputDevice) { . . . }
}
Client Code:
r:Rectangle := new Rectangle; cr:ColoredRectangle := new ColoredRectangle; . . . print(r.area()); print(cr.area()); r.draw(. . .); cr.draw(. . .);
Inheritance achieves code sharing by factoring code into common superclasses
May model real world scenarios well?
Inheritance is often over used by novices
Code gets fragmented into small factored pieces (this is good and bad)
Tracing control logic of code is harder
Perhaps inheritance with only extensions and overriding is too limited?
Dynamic binding allows subclass to be used wherever a superclass is expected, thus reusing superclass's code for subclass.
A subclass can be assigned to a variable of superclass type.
r:Rectangle := . . .; cr:ColoredRectangle := . . .; . . . r := cr;
When invoking operations on an object, the run-time system locates and invokes the right operation for the object.
r.draw(); // invokes draw for ColoredRectangle
This is called subtype polymorphism.
Dynamic binding requires run-time class information for each object.
Dynamic binding is also known as: message passing, virtual function calling, or generic function calling.
What happens at run-time to implement dynamic binding? Consider the following code: obj.msg(args).
Start with the run-time class C of obj (the receiver)
If a match is never found, report a run-time error.
Dynamic binding is similar to overloading in the following ways.
Dynamic binding is unlike overloading in the following ways.
Without inheritance and dynamic binding:
forall s:Shape in scene do
if s.is_rectangle() then
rectangle(s).draw(. . .);
else if s.is_square() then
square(s).draw(. . .);
else if s.is_circle() then
circle(s).draw(. . .);
else
error(. . .);
end
end
With inheritance and dynamic binding:
forall s:Shape in scene do
s.draw(. . .);
end;
What changes do I need to make in these two code fragments if I add a new subclass to Shape?
Dynamic binding allows subtype polymorphism and class-specific methods.
Dynamic binding allows subclasses to be added without modifying clients.
Dynamic binding can make the logic of the program harder to follow and reason about.
Dynamic binding adds some run-time overhead.