View
214
Download
0
Category
Preview:
Citation preview
1
Object Orientation
James Brucker
2
History Questions
OO concepts of encapsulation, inheritance, and polymorphism are based on what language developed in the 1960's in Norway?
What OO language introduced the notion of "message passing" between object?
What modern OO language uses message passing?
you can try to invoke any method of any object at runtime. If the method is "private" you get a runtime exception.
Hint: used in mobile phones
3
Questions 2
In Java, what is escape analysis and what is its purpose?
What is the difference between a value type and a reference type?
In C#, how are value types implemented?
In C#, can you add a method to a class that already exists? How?
4
Objectives
Motivation for O-O Languages
Key Characteristics
Important Differences
Focus on C++, C#, Java, and JavaScript
Implementation of O-O Features
Organization of Data Members
Virtual Method Table (VMT)
Dynamic Binding
5
Designing a Stack
A basic data structure. What behavior is needed?
push( value ) Put a new value on top of stack.
pop( ) Pop and return the top of stack
isEmpty( ) Test if stack is empty.
isFull( ) Test if stack is full.
Pretty simple, huh?
Let's see how C handles this.
Stack
push( ): voidpop( ): valueisEmpty( ): boolisFull( ): bool
6
Stack in C (1): imperative style
Can you name some deficiencies in this code? (find 4)
void push( int value, int *stack, int *top, int size ) {
if ( *top >= size ) perror("Stack overflow");
stack[(*top)++] = value;
}
int pop( int *stack, int *top, int size ) {
if ( *top <= 0 ) perror("Stack underflow");
return stack[--(*top)];
}
int isEmpty( int *stack, int *top, int size) {
return (*top <= 0);
}
7
Stack in C (2): simplify the interface
What are the problems with this implementation?
int SIZE = 0;int *stack;int top = 0;int initStack( int size ) {
stack = (int *)malloc( size * sizeof(int) );if ( stack == null ) perror("InitStack failed");SIZE = size; top = 0;
}void push( int value ) {
if ( top >= SIZE ) perror("Stack overflow");stack[top++] = value;
}int pop( ) {
if ( top <= 0 ) perror("Stack underflow");return stack[--top];
}
int isEmpty( ) { return (top <= 0); }
Global variable for stack properties.
8
Stack in C (3): hide data members
What are the problems with this implementation?
static int SIZE = 0;static int *stack;static int top = 0;int initStack( int size ) {
stack = (int *)malloc(size*sizeof(int));if ( stack == null ) perror("InitStack failed");SIZE = size; top = 0;
}void push( int value ) {
if ( top >= SIZE ) perror("Stack overflow");stack[top++] = value;
}int pop( ) {
if ( top <= 0 ) perror("Stack underflow");return stack[--top];
}
int isEmpty( ) { return (top <= 0); }
Data Hiding: "static" variables have file scope.
9
Stack in Modula-2: abstraction
TYPE element = integer;MODULE Stack;IMPORT element;EXPORT push, pop, isFull, isEmpty;CONST size = 100;VAR data : array [1..size] of element;
top : integer;PROCEDURE push( value : element );BEGIN
if top = size THEN error("Stack overflow");else begin
top := top + 1;data[top] := value;
end;END push;
Module limits scope/accessibility of its members. Import/export external names.
Better: abstract data type, data hiding, less name space pollution. Problems?
(* Stack usage *)
push( data1 );
push( data2 );
y := pop( );
10
Stack Factory in Modula-2MODULE StackFactory;IMPORT element;EXPORT stack, push, pop, isFull, isEmpty;CONST size = 100;TYPE stack = RECORD
data : array [1..size] of element; top : integer;
END;PROCEDURE init_stack(var stk : stack);BEGIN
stk.top := 1;END init_stack;PROCEDURE push(var stk: stack; item: element);BEGIN
if stk.top >= size then error( );else stk.data[stk.top] := item;stk.top := stk.top + 1;
END push;
(* Stack is abstract type *)
var A, B: stack;
init_stack( A );
init_stack( B );
push( A, data1 );
push( B, data2 );
11
Three Pillars of O-O Programming Encapsulation
objects contain both data and methods that operate on the data
control over visibility (and access) to members Inheritance
one class can extend another class, inheriting its attributes and methods. Promotes code re-use.
Polymorphism the same behavior can be defined for different classes a reference variable can refer to different classes using a reference, a program can transparently invoke
a named behavior from different classes.
12
Other benefits of object-orientation
Reuse code using well-designed classes and inheritance. Limit complexity by dividing big project into classes. Better control over object creation (constructor) and
destruction (finalizer or destructor).
class DancingButton extends JButton {
public DancingButton( ImageIcon image ) {
___________( image ); // call parent constructor
this.image = image;
}
public void paint( Graphics g ) {
_______________( g ); // call parent's paint( )
dancer.dance( );
}
13
Stack class in C++ (1)using namespace std;class Stack {private:
int *stack;int size;int top;
public:Stack( int asize ) : size(asize) { // constructor
stack = new int[asize];top = 0;
}~Stack( ) { // destructor
delete [ ] stack;}void push(int value); // method prototypeint pop( );
}; semi-colon ends class definition.
14
Stack class in C++ (2)class Stack {public:
...void push(int value);int pop( );bool isEmpty( ) { return top <= 0; }bool isFull( ) { return top >= size; }
};
void Stack::push(int value) {if ( top >= size ) perror("Stack overflow");stack[top++] = value;
}int Stack::pop( ) {
if ( top <= 0 ) perror("Stack underflow");return stack[--top];
}
Methods defined outside of class.
Method prototype inside of class.
15
Stack class in C++: header file
#ifndef _STACK_H_#define _STACK_H_class Stack {private:
int *stack;int size;int top;
public:Stack(int size) { ... }void push(int value);int pop( );bool isEmpty( ) { return top <= 0; }bool isFull( ) { return top >= size; }
};#endif
stack.h
16
Stack class in C++: method definition
#include "stack.h"void Stack::push(int value) {
if ( top >= size ) perror("Stack overflow");stack[top++] = value;
}int Stack::pop( ) {
if ( top <= 0 ) perror("Stack underflow");return stack[--top];
}
stack.cc
17
Why 2 Files?
#include "stack.h"void Stack::push(int value) {
if ( top >= size ) perror("Stack overflow");stack[top++] = value;
}...
stack.cc
class Stack {public:
Stack(int size) { ... }void push(int value);int pop( );bool isEmpty( ) { return top <= 0; }bool isFull( ) { return top >= size; }
};
stack.h
18
What belongs in stack.h?
#ifndef _STACK_H_#define _STACK_H_class Stack {private:
int *stack;int size;int top;
public:Stack(int size) { ... }void push(int value);int pop( );bool isEmpty( ) { return top <= 0; }bool isFull( ) { return top >= size; }
};#endif
why code here?
19
Stack class in C++: application
#include "stack.h"int main( ) {
Stack mystack(20); // creates a Stack objectmystack.push(1);mystack.push(15);...
}
application.cc
20
Encapsulation (1)
C++: extends C, functions and variables can be global, file, or class scope.
int MAXSIZE = 1024;
char buf[MAXSIZE];
static int size = 0;
int fun( ) { ... }
class Stack {
private:
int size;
int top;
public:
void push(int x);
...
};
C# and Java: all functions and variables must be part of a class.
public class Stack {
private int top;
private int size;
private int *stack;
public void push(int x)
{ if (top>=size) ...;
stack[top++] = x;
}
public bool isEmpty( )
{ return top <= 0;
}
}
21
Encapsulation (2)
C++: members can be public, protected, or private, but not classes.
class Stack {private:
int top;int size;
protected:int *stack;
public:void push(int x);bool isEmpty( ) {
return top <= 0;}
};
C#: class can be public, private, or internal.
public class Stack {private int top;private int size;protected int *stack;public void push(int x){ if (top>=size) ...;
stack[top++] = x;}public bool isEmpty( ){ return top <= 0;}
}
22
Scope of Names
C++ and C#: namespace and "using namespace" control name visibility.
using System;
using System.Collections;
namespace MyCollection {
class Stack {
...
}
}
Java: package and "import".
package mycollection;
import java.io.File;
import java.util.*;
class Stack {
...
}
/* C++ */
using namespace System;
using namespace System::Collections;
23
Scope Resolution Operator
C++ uses "::" but "." for elements of a class.
C# uses "."
/* C# */class Stack :System.Collections.IEnumerator { void read( ) {
Console.ReadLine( ); }
}
Java uses "."
/* Java */class Stack implements java.util.Iterator {
java.util.Scanner in =new java.util.Scanner();void read( ) { in.nextLine( );}
}
24
Creating Objects
C++, C#, and Java all have constructors. A class may have multiple constructors.
In C++ declaring an object reference constructs it!
In C# and Java, must use "new" to create the object.
/* C++ */
Person p; // invokes default constructor
Person p("Joe"); // invokes Person::Person(string)
Person& q = p; // create object reference q
/* C# and Java */
Person p; // create object reference only
p = new Person("Joe");// invokes Person(String)
25
Inheritance
C++:
multiple inheritance
no universal base class
C#:
single inheritance
all classes are subclass of System.Object
a class can implement unlimited number of interfaces
Java:
single inheritance
all classes are subclass of java.lang.Object
a class can implement unlimited number of interfaces
26
Inheritance and Access Control
Class members can be public, private, or protected. Child class inherits everything but can only access
public and protected members.
/* C++ */class Stack {protected:
int top;int size;int *stack;
public:void push(int x);bool isEmpty( ) {
return top <= 0;}
};
/* C# */public class Stack {protected int top;protected int size;protected int *stack;public void push(int x) { ... }public bool isEmpty( ) {
return top <= 0;}
27
Access Control in C++
"Friend" classes can access protected and private members.
Child class can reduce visibility of inherited parts.
class CircularStack : private Stack {...friend class StackManager;friend int max( const Stack& );
};
28
Multiple inheritance in C++
Multiple inheritance allows subclasses to "mix in" the properties of several parent classes.
class iostream: public istream, public ostream {
public: iostream( streambuf* ); virtual ~iostream();
protected: iostream( );
}
istream ostream
iostream
29
Multiple inheritance in C++ If a subclass has multiple paths to a superclass, it may inherit more than one copy of superclass properties! This is called repeated inheritance. This can cause unwanted,
inconsistent behavior.
A
B C
D
A
class A { protected string name; ...};class B : public A {...};class C : public A {...};class D : public B, public C {...};...D dog(); // dog has 2 copies of A::namedog.setName("woof"); // set which name?
30
Shared inheritance in C++
Shared inheritance: instances of a derived class that have multiple access routes to superclass share the same instance of a superclass object:
A
B C
D
class A { protected string name; ...};class B : virtual public A {...};class C : virtual public A {...};class D : public B, public C {...};...D dog( ); // dog has only one A::name member
31
Polymorphism
Polymorphism enables flexible, extensible applications.
JButton button = new JButton(...);JTextField text = new JTextField(...);JSlider slider = new JSlider(...);container.add( button );container.add( text );container.add( slider );
Container
-components: Collection
+add( JComponent)
+paint(Graphics g)
JComponent
paint(Graphics g)setsize( Dimension )setPosition(Dimension)...
JButton
JSlider
JTextField
1 *
JPanel
32
Polymorphism (2)
Container can send same message to any JComponent.
/* tell all components to paint themselves */for( JComponent comp : components )
comp.paint( Graphics g );
Container
-components: Collection
+add( JComponent)
+paint(Graphics g)
JComponent
paint(Graphics g)setsize( Dimension )setPosition(Dimension)...
1 *
JavaVM will call the paint(Graphics) method of each object, not the paint method of the superclass (JComponent).
33
Liskov Substitution Principle
If a program uses an object from class A, then
the program should still work correctly if you
substitute an object from any subclass of A.
For this to work, the behavior of each public method in a class needs to be clearly defined.
This means documentation.
Java and C# include documentation right in the code.
34
Polymorphism in Java
class Person {protected String name;...public String toString( ){ return name; }
}class Student extends Person {
private String studentID;...public String toString( ) { return studentID; }
}
In Java, instance methods use dynamic binding so polymorphism is automatic.
Person p = new Student("Bill Gates", "11111111");System.out.println( "Welcome to KU " + p.toString() );
35
Static Binding in Java
class Person {private static int nextID;
public Person( ) { ... }final void setName( String newname ) { ... }private void initialize( ) { ... }public static getNextID( ) { return nextID; }
}
Static binding used for things that are never overridden: static and final methods private methods constructors.
36
Polymorphism in C++
class Person {protected: string name;public:
Person(string aname) : { name = aname; }string toString( ) { return name; }
}class Student : Person { /* Student extends Person */
protected: string id;public:
Student(string name, string id) : Person(name),id(id) { }
string toString( ) { return id; }}
All methods are statically bound unless virtual.
Student bill("Bill Gates", "11111111");Person &p = bill; cout << Welcome to KU " << p.toString() << endl;
37
Polymorphism in C++ virtual methods are dynamically bound. virtual can applied to classes, methods, and abstract methods.
class Person {protected: string name;public:
Person(string aname) : name(aname) { }virtual string toString( ) { return name; }
}
class Student : Person { /* Student extends Person */protected: string id;public:
Student(string name, string id) : Person(name),id(id) { }
string toString( ) { return id; }}
38
Polymorphism in C#
Static binding (default)
Use "new" to override.
class Person {public string who( ){ ... }
}class Student : Person {
new public string who(){ ... }
}
Dynamic binding: use virtual and override.
class Person {public virtual string
who( ){ ... }
}class Student : Person {
public override string who( )
{ ... }}
Person p = new Student("Bill Gates", "11111111");p.who( );
Example:
39
Why static binding?
Polymorphism is key to writing extensible, reusable O-O programs.
So, why don't C# and C++ always use dynamic binding?
don't require us to request it using "virtual"
Why does Java have "final" methods? eliminates future opportunity for overriding
40
Polymorphism and Run-time Binding
A key to polymorphism is that names are bound to methods dynamically.
How does the run-time environment know which method should be used?
public class Circle extends JComponent {void paint(Graphics g) { /* draw circle */ }...
}public class Square extends JComponent {
void paint(Graphics g) { /* draw square */ } ...
}public redraw( Graphics g ) {
JComponent [ ] parts = { new Square(), ... };parts[k].paint(g); // determined at run-time
41
Memory for Object Data Members
class Person {String name;Date birthday;char sex;... // methods String getName() ...
}
void test( ) {Person you =
new Person(...);you.name = "Mr. Java";you.getName( );}
you VMT ptr
name
birthday
'M'
memory
Virtual Method Table for Person
a String object
a Date object
42
Memory for Object Data Members
you VMT ptr
name
birthday
'M'
memory for Person
Virtual Method Table for Person
a String object
a Date object
The compiler uses known offsets from the start of object for each data member. For example:
you.name is (you)+4
you.sex is (you)+12
The VMT is for accessing methods (later).
43
Memory Layout with Inheritance
class Person {String name;Date birthday;private char sex;// methodsString toString( )...
}class Student
extends Person {String studentID;Course [] courses;void addCourse(...)
}s = new Student(...);
s VMT ptr
name
birthday
sex
memory for StudentVMT for Student
String
Date
studentID
courses
String
Array
Person
44
Virtual Method Table for Object
A Virtual Method Table is a table of addresses of the methods of a class. For the Object class...
clone
equals
finalize
getClass
...
toString
address of Object clone method
address of Object equals method
address of Object finalize methodMethods from Object's VMT
The compiler knows which method it wants based on signature. It can specify as offset in runtime VMT.
45
Virtual Method Table for Person A subclass can add methods or replace methods in its VMT. Only 1 VMT for each class (all objects share it).
clone
equals
finalize
getClass
...
toString
getName
setName
address of Object clone method
address of Person equals method
address of Object finalize method
Methods from Object's VMT
(maybe changed by Person class)
Methods added by Person class
address of Person toString method
46
Object Reference and Inheritance The information about an object is available through the object reference.
Person p = new Person(...);
p VMT ptr
name
birthday
sex
String
DatePerson
clone
equals
finalize
getClass
...
toString
getName
setName
memory for Person object VMT for Person class
47
Object Reference and Inheritance A subclass can override fields/methods or add new fields and methods.
Student s = new Student(...);
s VMT ptr
name
birthday
sex
String
Date
studentID
courses
String
Array
Person
clone
equals
finalize
getClass
...
toString
getName
setName
getCourse
addCourse
addedattributes
addedmethods
memory for Student object VMT for Student class
48
Object Reference and Inheritance If we assign an object to reference of superclass type, the extra information is still there, but
not used by superclass reference.
Person p2 = new Student();
p2 VMT ptr
name
birthday
sex
String
Date
studentID
courses
clone
equals
finalize
getClass
...
toString
getName
setName
getCourse
addCourse((Student)p2).getCourse();
49
Interfaces Separate the specification of behavior from the implementation
of the behavior. Interfaces can often replace multiple inheritance. Interfaces can extend other interfaces in Java and C#
Example: IComparable specifies "CompareTo" behavior.
/** C# IComparable interface **/namespace System {
public interface IComparable {int CompareTo( object other ) ;
}}
method signature onlymethods are automatically "public"
50
Interface Example
/** Person class implements IComparable **/using namespace System;public class Person : IComparable {
private string lastName;private string firstName;...int CompareTo( object other ) {
if ( other is Person ) {Person p = (Person) other;return lastName.CompareTo( p.lastName );
}else throw new ArgumentException(
"CompareTo argument is not a Person");}
}}
Why implement interface?
What is the benefit?
51
/* System.Array provides utilities for arrays */public class Student : Person { ... }public class Registrar {
...Student [ ] iup = new Student[100];Array.Sort( iup );Array.BinarySearch( iup, new Student("Shinawat") );Array.Reverse( iup );
Array+Sort( IComparable[ ] )+Reverse( IComparable[ ] )+BinarySearch( Array, Obj)
IComparable
+CompareTo( object ): int
Person
Student
*
52
Strategy Design Pattern
Context: A class requires a (complex) behavior, but there are many alternatives that can be used.
Solution: implement the behavior in a separate class, called the Strategist.
Create a Strategy interface to de-couple the context class from the Strategist.
Context
- strategy: Strategist
+setStrategy( Strategist )
Strategist
+doSomething( )...
ConcreteStrategy
+doSomething( )...
AnotherStrategy
+doSomething( )...
What are some examples of this?
53
Observer Design Pattern
Context: An object (the Subject) is the source of interesting events. Other objects (Observers) want to know when an event occurs.
Solution: (1) Subject provides a method for Observers to register themselves as interested in the event.
(2) Subject calls a known method (notify) of each Observer when event occurs.
Subject
- observers: Collection
+addObserver( Observer )
+removeObserver( ... )
Observer
+notify( event: Object )...
ConcreteObserver
+notify( event )...
AnotherStrategy
+notify( event )...
What are some examples of this?
54
Observer Pattern in Java
The hard part is writing the Subject class methods to manage and notify observers. Java does this for you: java.util.Observable
YourApplication
-event( )
...
Observer
+update( Observable, Object )
YourFriendsObserver
+notify( event )...
Observable
- observers: Collection+addObserver( Observer )+deleteObserver( ... )+notifyObservers( Object )
addObserver(this)
event( ) {setChanged( );notifyObservers(obj);
}
55
C# Delegates
Delegate is a type in the C# type system. It provides a way to pass a function name as argument. Can act as a collection for observers.
/** define a delegate that accepts string **/public delegate void TellMe( string msg );
/** create some delegates **/TellMe observers = new TellMe( out.WriteLine );observers += new TellMe( button.setText );observers += new TellMe( textarea.append );/** call all the observers at once! **/observers("Wake Up!");
56
Garbage Collection
C++ does not require automatic garbage collection. programmer must explicitly free memory that he
allocated with "new" use destructor to free resources inside of objects memory leaks are a problem
C# and Java have automatic garbage collection reduces need for destructor (Java: finalize) gc impacts performance... for better or worse
57
Operator Overloading
C++ lets you redefine operators for new types.
Example: Suppose you have a complex class for storing complex numbers.
We'd like to be able to operate on and compare complex objects just like double, float, ...
complex z1(2,1); // z1 is 2+1i
complex z2(1,4); // z2 is 1+4i
complex z3 = z1 + z2;
cout << "z3 = " << z3; // prints z3 = 3+5i
if ( z3 == 0 ) cout << "zero".
58
Operator Overloading
In C++ you can refer to any infix, prefix, or postfix operator as operatorop.
z1 + z2 is the same as:
z1.operator+(z2) // operator+ is a method
operator+(z1,z2) // operator+ is a function
In the first case, operator+(complex) is a member of the complex class, so it can access the private attributes.
In the second case, operator+ is not part of the class.
But you can declare it a "friend" function to give it access to private attributes.
59
Overload as Method or Function?
If you declare operator+(Complex z2) inside the class then its a method.
If you declare operator+(Complex z1, Complex z2) outside the class, then you're declaring a function.
Which way is better? in this case we'd like to able to write z+1.0 or 1.0+z when z is a complex number. "1.0+z" won't work as a method since 1.0 is a double, not a Complex object. So implementing as a function allows symmetric behavior. the advantage of implementing as a method is that the method has access to private attributes of the class.
z1.operator+(z2); // operator+ is a methodoperator+(z1,z2); // operator+ is a function
60
Operator Overloading Example (1)
class complex {private:
double real, imag; // real and imaginary partspublic:
complex(double re=0, double im=0) {real = re; imag = im;
}// define "+" as a methodcomplex operator+(const complex& z) {
return complex(real+z.real, imag+z.imag);}// define "==" as a methodbool operator==(const complex& z) {
return (real==z.real && imag==z.imag);}
61
Operator Overloading Example (2)
class complex {private:
double real, imag; // real and imaginary partspublic:
complex(double re=0, double im=0) {real = re; imag = im;
}// define "+" as a friend functionfriend complex operator+(const complex&,
const complex&);
For operations that (1) don't modify their arguments, or (2) the first argument may not be of the class type, it is simpler to define as an ordinary function (not part of class).
62
Operator Overloading Example (3)
// definition of "+" is outside of class:complex operator+(const complex& u,
const complex& v) {return complex(u.real+v.real, u.imag+v.imag);
}
Notice that in this case, both arguments to "+" are parameters to the function.
C++ will invoke this function for complex+complex, complex+double, and double+complex ... after converting double to complex.
63
C# Type System In C#, all data types are either objects or structs. int, double, bool, etc., are implemented as struct. struct are value data types. struct "inherit" from System.ValueType struct are compatible with Object root class
Object reference data typeheap dynamicgarbage collected inheritance and interfacesallocate with "new"polymorphic (maybe)
Structvalue data typeany memory areastack management applies interface, no subclassesallocated by variable declaratonnot polymorphic; op. overload
64
Fraction Struct
struct Fraction {long num; // numerator and denominatorlong denom; // could be "private" if we wantpublic Fraction(int num, int denom) {
this.num = num; this.denom = denom; // ToDo: gcd}public Fraction(int num) { this.num = num; denom = 1; }public static operator+(Fraction f1, Fraction f2) {
return new Fraction(f1.num*f2.denom+f1.denom*f2.num, f1.denom*f2.denom);
}// output Fractionpublic override string ToString( ) {
if (denom==0 && num==0) return "NaN";... // other cases go herereturn num.ToString() + "/" + denom.ToString();
}
65
Struct is value type, Object is reference
class FractionTest {void Test( ) {Fraction a = new Fraction(1,2);Fraction b = a;a.num = 7;Console.WriteLine("b={0}", b);
}
struct Fraction {int num, denom;... define struct
}
class Fraction {public int num, denom;... define class
}
What is the output in each case? struct Fraction class Fraction
66
How does a method get a value for "this"?
Recommended