1 Object Orientation James Brucker. 2 History Questions OO concepts of encapsulation, inheritance,...

Post on 29-Dec-2015

214 views 0 download

Transcript of 1 Object Orientation James Brucker. 2 History Questions OO concepts of encapsulation, inheritance,...

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"?