Chapter 12

handprintΛογισμικό & κατασκευή λογ/κού

18 Νοε 2013 (πριν από 3 χρόνια και 8 μήνες)

110 εμφανίσεις

Object
-
Oriented Programming


Objects were first introduced in Simula 67


although the intent in Simula was not to provide a new programming
paradigm, but instead to offer a construct to easily build models for
simulation purposes


OOP was developed fully in Smalltalk


the object can be thought of as an extension to ADTs except that the
structure can be extended for easy modification leading to a hierarchically
organization


message
-
passing was implemented rather than function calls


encapsulation was enforced through the class construct


different types of objects call upon the same method if the objects were related
hierarchically, leading to polymorphism and generic methods


OOPL was later included in many languages


C++ (a descendent of C with many of Smalltalk’s class ideas)


Common Lisp (added to CL was CLOS, the Common Lisp Object System)


Ada 95 (Ada 83 + objects)


Java and C# introduce a newer generation of OOPLs related to C++ but
cleaner and easier to understand


Scripting languages started adding objects with JavaScript and has continued
with both Python and Ruby (Ruby is the only
pure
OOPL since Smalltalk)

OOPL Definitions


Pure OOP: all computation done by message passing


Hybrid OOP: computation shared between message passing and
function calls


most OOPLs are hybrids (C++, Ada 95, Delphi, Common Lisp, C#)


Java would be pure if not for the 8 primitive types


Inheritance: to solve the modification problem; controls what
definitions a subclass obtains from a parent class


to control inheritance, the language might include modifiers such as
private
,
public
and
protected


question: can a subclass override a parent’s definition?


if so, can the parent item still be accessed or is it hidden?


question: is multiple inheritance available? (C++ and CLOS have this)


Polymorphism: variables that can reference any subclass of a given
class


we need a mechanism to bind a message to the proper method, which is often
done at run time so is called
dynamic type binding

Class/Subclass Relationships


Aside from C++ and Common Lisp, classes in other
languages must have one (and only one) parent


any defined class needs a parent, what is that parent’s parent?


with this restriction, such languages will offer a starting class


usually called Object


what if a parent class is not specific enough to have an
implementation for its methods but all child classes should
have the given methods?


in this case, we can make the methods in the parent class
abstract
(also
known as
virtual
)


this forms what is known as an
interface
in Java


an interface means that the pre
-
specified abstract methods
must
be
implemented in any class that implements (inherits from) the interface


classes with abstract entities cannot themselves be instantiated, but can
be extended into subclasses

Design Issues


Exclusitivity of Objects


are all types classes, or are there other types?


dictates whether all communication is via message passing or if other
forms are provided and whether the language is pure OOP or hybrid


Subclass relationships


is a subclass a descendant of the class (
is
-
a

relationship)


or some different relationship such as a subrange or subset


Inheritance and information hiding


how are these provided? is information hiding enforced?


Type checking and polymorphism


is type checking done and if so, when?


can variables be polymorphic?


Single vs. multiple inheritance


which is allowed?


Allocation and Deallocation of Objects


when and how is this performed?

Note: we will explore

sample programs from

many of the languages

discussed here on
-
line

so this set of notes largely

omits specific examples

Smalltalk


Programs consist only of objects and messages


variables are local (private) or global (shared)


all vars are pointed to by ptrs


inheritance


single inheritance only, subclasses inherit everything from the parent


class methods/data


can be overridden in the derived class


the parent’s methods/data are only hidden but still accessible (using super)


Dynamic binding for polymorphism


when a method is called, a search takes place at the child’s
location for that method’s definition


if not found, the search continues up the hierarchy until the
method’s definition is found (if none found, error)


if parameters and return type are the same for all classes that a
polymorphic variable can take on, then type checking can be done at
compile time, otherwise it is done at run
-
time

Smalltalk Messages and Methods


All items in Smalltalk are objects, so all
operations are methods and specifying actions is
done strictly through message passing (even if it
doesn’t look like it!)


messages contain


object for whom the message is sent


method to invoke


any needed parameters


some examples:


21 + 2

// object 21 receives message + and parameter 2


sum / count //sum receives message to divide by count


firstArray at: 1 put: 5 // firstArray gets message at with






// parameter 1 and put 5, or






// firstArray[1] = 5;


ourPen home; up; goto: 500@500; down; home




graphics routine with multiple messages passed to ourPen

Message Types Continued


3 forms of methods:


unary methods (message without params)


binary methods (as with 21 + 2 or sum / count,
mostly used for arithmetic operations)


and the general form shown below where key# is a
keyword for the object


key1: param1 key2: param2 … key n: param n


Assignments statements operate as follows


any message expression, variable or literal object on
RHS


LHS is a data instance


total


22


sales


deducts grossPay: 350.0 dependents: 4

Defining a Class


Much like Java, you define your class, its variables
and its methods


In Smalltalk, you have class variables and instance
variables


class variables are like Java’s static instance variables


that is,
you define a variable to be
classwide


The notation is:


Object subclass: #
superclassname


instanceVariableNames
: ‘’


classVariableNames
: ‘’


poolDictionaries
: ‘’


Category: ‘
classname



If you have variables to define in any section, separate
them by spaces within the ‘’ as in ‘x y z’


the
poolDictionary

contains variables that are not owned by
this class, so you can use this to define global variables that this
class might manipulate


bad idea of course!

Defining Methods


Since Smalltalk is interpreted, you typically define
your methods interactively
after
you have defined
your class rather than wrap them up in a single
definition


Methods by default do not expect to receive parameters


If you want your method to receive a single parameter,
add :
param

after the method’s name as in


setX
:
newValue


If you have multiple parameters, you must have specific
keywords for all but the first as in


setValues
: val1 Value2: val2 Value3: val3


In this case, you would call the method as
setValues
: 5 Value2: 3
Value3: 10


Local variables are declared in | | notation as in | x y z |


To return a value at the end, use ^
returnvalue

Example: Point

Object subclass: #NameOfSubclass


instanceVariableNames: ‘p1 p2'


classVariableNames: ''


poolDictionaries: ''


category: 'Point‘

getP1


^p1.

getP2


^p2.

init: x second: y


p1:=x.


p2:=y.

distance: point2


| temp1 temp2 |


temp1:=(p1
-

point2 getP1)*(p1


point2 getP1).


temp2:=(p2
-

point2 getP2)*(p2


point2 getP2).


^ (temp1


temp2) sqrt.

Here is how we can interact with Points:


point1 := Point new.


point1 init: 5 second :10.


point2 := Point new.


point2 init: 12 second :7.


point1 distance: point2.

Blocks and Control Structures


Blocks are specified in [ ] with instructions separated by .’s


block code is only executed when the message
value
is sent to the block


addIndex


[sum <
-

sum + index]


addIndex value


value is a message to addIndex to execute the block


Blocks can contain relational expressions and return True or
False providing a mechanism for conditional blocks


conditional blocks can be used to form a pretest loop method called
whileTrue:


x


1. sum


0. [x <=20]





whileTrue: [sum


sum+x. x

x+1]


another loop is timesRepeat: which is provided an integer value


Selection statements use ifTrue and ifFalse as in


[x > 0] ifTrue: [y


x + 1. x


x


1] ifFalse: [y


0.]

Evaluation of Smalltalk


Small language, simple (?) syntax


mathematically limited


less efficient than imperative languages


because of dynamic type checking, errors often not caught until run
-
time


First real OOPL and the only pure OOPL until Ruby


successor languages did not like to force everything to be message passing
and therefore most OOPLs are hybrids of some form


Smalltalk pioneered many of the ideas found common in all
OOPLs


LOGO was a system built using Smalltalk to provide a graphical
programming environment


objects are windows, menus, cursor, lines, …


messages include down, up, turn:degrees, go:distance, goto: point, home,
north, …


Pen is the general class designated to draw


To draw a triangle:


OurPen

Pen new defaultNib: 2.


OurPen up; goto: 800@300; down


OurPen go: 100; turn: 120; go: 100; turn: 120; go: 100

C++


Based on C (same types) but adds classes


updates Smalltalk’s object system as follows:


classes can either be a derived class (from a superclass) or stand alone
without having a superclass


some or all data and functions can be inherited from base class(es)


objects can be either stack dynamic or heap dynamic (these require a
destructor method to deallocate memory)


both forms require a constructor


whereas Smalltalk’s use of classes was consistent and fairly
simple (because the language itself was small), C++’s use of
classes is very complex and the language is quite large


C++ is the most used OOPL in spite of (or maybe
because of) having complex object
-
oriented mechanisms


such as multiple inheritance and complete flexibility in
controlling what is inherited

Controlling Inheritance


Class members can be
private, protected or
public


private members are only
accessible by member
functions and friends of
the class


friends are
functions/classes
explicitly declared as
friends by the given class


public members are
accessible by any function


protected members are
like private members
except that derived classes
can modify access rights
for inheriting members


class base_class {



private:



int a; float x;




protected:



int b; float y;




public:



int c; float z; }




class sub1 : public base_class {…};



class sub2 : private base_class {…};



in sub1: b and y are protected, c and z are public




in sub2: b, y, c and z are private and no derived


class of sub2 will have access to any of these



a and x are not accessible to sub1 or sub2


note that since sub2 is a derived private class, no member
of the parent class is explicitly visible, and so b, c, y and z
must be re
-
exported to be used in an instance of sub2


this is done using : : as in base_class : : c;

Example


class single_linked_list {


class node {


friend class single_linked_list;


private:



node *link;



int contents;


};


private:


single_linked_list( ) {head = 0};


void inset_at_head(int);


void insert_at_tail(int);


int remove_at_head( );


int empty( );


};


class stack : public single_linked_list {


public:


stack( ) { }


void push(int value) {


single_linked_list::insert_at_head



(int value);


}


int pop( ) {



single_linked_list::remove_at_head( );


}


};



class queue : public single_linked_list {


public:


queue( ) { }


void enqueue(int value) {


single_linked_list::insert_at_tail



(int value);


}


int dequeue( ) {



single_linked_list::remove_at_head( );


}


};


The nested inner class, node, lists


single_linked_list as a friend so that


single_linked_list can access node’s private parts


Both stack and queue extend

single_linked_list but both are public

derivations, we should restrict that by

making them private


see the code on

Page 540
-
542

C++ Object Binding


Objects can be referenced through ordinary variables


these objects are stack dynamic and all method calls would be
statically bound


Otherwise, objects are referenced via pointers


these objects are heap dynamic


any pointer of a class can point at any derived class of that
class


thus, pointers can be polymorphic variables


but non
-
pointers cannot


if the variable is polymorphic then method calls are
dynamically bound


any method that will be dynamically bound must be declared
as a
virtual
function

Example

public class shape {


public:


virtual void draw( ) = 0; // indicates that draw is a pure virtual function


}




// that is, that there is no implementation here





// so shape is an
abstract

class


public class circle : public shape {


public:


virtual void draw( ) {…}


}



public class rectangle : public shape {


public:


virtual void draw( ) {…}


}



public class square : public rectangle {


public:


virtual void draw( ) {…}


}



square s;


// s is dynamically


rectangle r; // bound to draw


shape &ref_shape = s;


ref_shape.draw( );


// whereas r is statically


r.draw( );


// bound to draw

Java


Most of you are familiar with Java, so we will only cover a few highlights of
objects in Java


all entities in Java are objects except for the primitive types so all Java
programs require class definitions


the class with the main method is an object that creates or calls upon all other
objects


Java restricts inheritance to single inheritance


all objects must have a parent (no stand
-
alone objects), by default, the parent is
Object


multiple inheritance can somewhat be simulated through interfaces


all objects are heap dynamic and pointed to by reference variables (a
pointer that does not require dereferencing)


all method calls are dynamically bound (unless a class is denoted as final
which means it can not be extended, so it will not have subclasses)


Java includes a finalize method that will be invoked before the object’s
memory is returned to the heap


Java has no destructor since garbage collection is used


Java is simpler and less powerful than C++


but that might be a good thing!

C#


C# offers constructs for the class (similar to Java) and
struct (similar to C++)


structs are stack dynamic, objects are heap dynamic


C#’s syntax is more like C++ for class definitions, for
example:


public class NewClass : ParentClass {…}


dynamic binding is done only if methods are specially
indicated as
virtual
where overridden methods in derived
classes must be specially indicated through the word
override


classes that contain abstract methods must be declared as abstract and
abstract classes cannot be instantiated (see page 534 for example)


like Java, C# offers only single inheritance and all classes
must have a parent (no stand
-
alone classes) with the parent
class defaulting to Object


the Object class implements ToString, Finalize and Equals, which are
inherited to all classes

Objects in Ada 95


Ada 83 included the Package for encapsulating ADTs


Objects were added for Ada 95 as an extension for this


Objects became a new type called a
tagged
type


Tagged types are either records or private types


private types are true objects as they offer information hiding


Packages can be separately compiled giving Ada 95 the ability to offer
classes much like Java, C++, and C#


Ada offers both static and dynamic binding of objects to
procedure calls


Dynamic binding is available through the tagged type’s classwide type
denoted as Name’class or by using a polymorphic variable


Ada objects:


No implicit calling of constructors and destructors


if desired, they must be invoked explicitly, but they are not needed


Single inheritance


although multiple inheritance can be simulated to some extent using generic
classes


Subclasses inherit all items from a parent class and to restrict this, you
would have to use child library packages (nested directly inside of the
parent’s package)

Ada Example

Package PERSON_PKG is


type PERSON is tagged private;


procedure DISPLAY(P : in out PERSON);


private



type PERSON is tagged


record



NAME : STRING(1..30);



ADDRESS : STRING(1..30);



AGE : INTEGER;


end record;

end PERSON_PKG;


with PERSON_PKG; use PERSON_PKG;

Package STUDENT_PKG is


type STUDENT is new PERSON with


record



GRADE_POINT_AVERAGE : FLOAT;



GRADE_LEVEL : INTEGER;


end record;


procedure DISPLAY (ST: in STUDENT);


end STUDENT_PKG;


Note:

DISPLAY is being overridden from

person_PKG


P : PERSON;


S : STUDENT;


Pcw : PERSON’class; // classwide





// version of Person


DISPLAY(P); // call Person’s display


DISPLAY(S); // call Student’s display


Pcw := P;


DISPLAY(Pcw); // Person’s display


Pcw := S;


DISPLAY(Pcw); // Student’s display

Ada’s mechanisms for objects is

built on top of previous mechanisms

and so is both awkward and less

flexible than C++, and inconsistent

as compared to Java/C#

Ruby


Like Smalltalk, everything in Ruby is an object and all
computation is done via message passing


class definitions are executable, meaning that a class’
definition (structure or available methods) can change at run
time


for instance, you could have code that modifies a class at run
-
time so
that the class gains a new method


at run
-
time, a class is the union of all definitions that have been
executed


all variables are reference variables to objects and all are
typeless


instance variable names are denoted by starting with @


instance variables are always private (accessor methods must be
written if you want to provide external access to an instance variable)


methods default to public, but can be private or protected


accessor/mutator methods can be easily generated by using
the shortcut functions attr_reader and attr_writer respectively


for instance: attr_reader :member1, :member2 will automatically
generate a getter method to return the value of member1

More on Ruby


Deriving a subclass is done through < as in


class subclass < parentclass


access control to methods can be changed at the subclass level (for
instance, if subclass above inherits method foo, subclass can alter the
access control from public to private or protected)


The Ruby module is used to control encapsulation and
namespaces


All variables are polymorphic (they are typeless and so only
bound to a given object when assigned to point at it) and are
therefore dynamically bound to methods


While Ruby is a pure OOPL (and therefore will satisfy some OO
programmers), it is generally a weaker language than C++, Java
or C# in that it lacks the ability to more tightly control


what is inherited and how (no multiple inheritance)


access control


other OOPL features like abstract classes

JavaScript


JavaScript


primarily use is for dynamic html pages


JavaScript is similar to Java in syntax and


JavaScript, like Java, uses two types of data


objects and primitive data types


but from there, the treatment of objects differs:


Java: statically typed language


JavaScript: dynamically typed language with all variables being
reference variables (implicit pointers) much like in Lisp


JavaScript: does not have a class, objects are created dynamically
without a formal definition


so JavaScript does not support inheritance or polymorphism


JavaScript does not require that variables be declared, but even if they
are, they do not have to be typed


types are determined when the variable is assigned a value, and the type
changes as the value assigned changes (much like Lisp)


any variable can reference any primitive type or any object

JavaScript Objects


Objects have a collection of properties


These properties are their data members and methods


each data member is a pair


the name and its current value


functions and methods are objects themselves and referenced by
variables which point to them


to create an any object,
new
is used, creating a blank object


example: var my_object = new Object( );


to add to an object, assignment statements are used


example: my_object.name = “Frank Zappa”; and my_object.occupation =
“musician”;


objects can be nested by now doing my_object.education = new Object( );
and assigning my_object.education.college = “none”;


if access is made to a property that does not exist, the value
undefined
is
returned


to remove from an object, use delete as in delete my_object.occupation;

More on JavaScript


Functions/methods are defined
similar to properties:


define the function


function f( ) {…}


assign a variable to point at the
function


var x = f


constructors are defined as ordinary
functions and called (if defined)
whenever new is used


example:


function musician(style, instrument,
age) {this.style = style;
this.instrument = instrument;
this.age = age);}


my_object = new musician(“rock”,
“guitar”, 37);


JavaScript is like Java in that
it contains


most of the same control
structures as Java


the same arithmetic operators
as Java and the same style of
assignment statement


many of the same String
operations as Java


JavaScript is not intended for
large
-
scale applications


so this primitive and flexible
treatment of objects is
satisfactory if you need objects
in your script


but if you want to do OOP,
you would
never
choose
JavaScript

Implementing Objects


To implement an object, there needs to be at least two mechanisms
available for easy construction and use:


a description of the data storage needed for the object


pointers to the object’s methods so that, if dynamically bound, the method
call can quickly be made


Both of these can be captured by having the compiler generate a
class instance record (CIR) at compile
-
time


any newly instantiated object uses the CIR as a template to generate the
storage space needed for the object


the CIR could contain a pointer to all methods, but either the CIR would
have to modified at run
-
time whenever the variable is altered to point at a
subclass (if the variable is polymorphic), or we would have to disallow
polymorphic variables


so we will use a different approach


instead, we might use a virtual method table for each class


this will differ for a
subclass


the CIR then points at the VMT for the class it is currently assigned to, and this
pointer changes whenever the variable is assigned to a different class

Example of CIRs


public class A {


public int a, b;


public void draw( ) {…}


public int area( ) {…}

}







public class B extends A {


public int c, d;


public void draw( ) {…}


public void sift() {…}

}

This becomes more complicated if multiple

inheritance is allowed, see figure 12.3 on page

563 to illustrate this in C++