Transcript chapter5
CSSE501 Object-Oriented
Development
Chapter 5: Messages, Instances
and Initialization
This chapter examines OOP run-time
features:
Object Creation and Initialization
(constructors)
Message Passing Syntax
Accessing the Receiver from within a
method
Memory Management or Garbage
Collection
Constructors
A constructor is a function that is implicitly invoked
when a new object is created. The constructor performs
whatever actions are necessary in order to initialize the
object
In C++, Java, C# a constructor is a function with the same name
as the class.
In Python constructors are all named __init__
In Delphi, Objective-C, constructors have special syntax, but can
be named anything. (Naming your constructors create is a
common convention)
class PlayingCard { // a Java constructor
public PlayingCard (int s, int r) {
suit = s;
rank = r;
faceUp = true;
}
...
}
Overloaded Constructors
Constructors are often overloaded, meaning there are a
number of functions with the same name. They are
differentiated by the type signature, and the arguments used
in the function call or declaration:
//C++ example
class Student
{
private:
int idNum;
string name;
double gradePointAverage;
public:
Student();
Student(int);
Student(int, string);
Student(int, string, double);
……
};
Student::Student()
{
idNum = 9999;
name = “J. Smith”;
gradePointAverage = 0.0;
}
Student::Student(int id)
{
idNum = id;
}
……
Student::Student(int id, string nm, double grade)
{
idNum = id;
name = nm;
gradePointAverage = grade;
}
//Java Example
class DigitalCounter {
private int counter;
private int minimum;
private int maximum;
public DigitalCounter() {counter = 0; minimum = 0; maximum = 9;}
public DigitalCounter(int counter, int minimum, int maximum) {
this.counter = counter;
this.minimum = minimum;
this.maximum = maximum;
}
//return the current counter value
public int getCounter() { return counter; }
public int getMinimum() { return minimum; }
public int getMaximum() { return maximum; }
public void setCounter(int counter) { this.counter = counter;}
public void setMinimum(int minimum) {this.minimum = minimum;}
public void setMaximum(int maximum) {this.maximum = maximum;}
}
public void increaseCounter() {
if (counter == maximum) counter = minimum;
else counter = counter +1;
}
Instances
Now, we could use constructors to create instances of
classes
C++
Student oneStudent;
Student twoStudent(7766, “Anna Moore”, 3.74);
Instances
Java
//a digital counter DC1 with minimum 0, maximum 9, and
//current counter value 0
DigitalCounter DC1 = new DigitalCounter();
//a digital counter DC2 with minimum 0, maximum 59, and
//current counter value 5
DigitalCounter DC2 = new DigitalCounter(5, 0, 59);
Object Creation
In most programming languages objects must
be created dynamically, usually using the new
operator:
PlayingCard aCard; // simply names a new variable
aCard = new PlayingCard(Diamond, 3); // creates the
new object
The declaration simply names a variable, the
new operator is needed to create the new
object value
Messages are not Function Calls
Recall from chapter 1 that we noted
the following differences between a
message and a function (or
procedure) call
A message is always given to some
object, called the receiver
The action performed in response is
determined by the receiver, different
receivers can do different actions in
response to the same message
Message Passing Syntax
Although the syntax may differ in
different languages, all messages have
three identifiable parts:
aGame.displayCard (aCard, 42, 27);
The message receiver: aGame
The message selector: displayCard
An optional list of arguments: aCard, 42,
27
Statically Types and Dynamically
Typed Languages
A distinction we will see throughout the
term is between the following:
A statically typed language requires the
programmer to declare a type for each variable.
The validity of a message passing expression
will be checked at compile time, based on the
declared type of the receiver (e.g., Java, C++,
C#, Pascal).
A dynamically typed language associates types
with values, not with variables. A variable is just
a name. The legality of a message cannot be
determined until run-time (E.g., Smalltalk,
CLOS, Python).
The Receiver Variable
Inside a method, the receiver can be accessed
by means of a pseudo-variable
Called this in Java, C++, C#
Called self in Smalltalk, Objective-C, Object Pascal
Called current in Eiffel
function PlayingCard.color : colors;
begin
if (self.suit = Heart) or (self.suit = Diamond)
then color := Red
else color := Black;
end
Implicit Use of This
Within a method a message expression or a
data access with no explicit receiver is
implicitly assumed to refer to this:
class PlayingCard {
... public void flip () { setFaceUp( ! faceUp ); }
...
}
Is assumed to be equivalent to:
class PlayingCard {
... public void flip () { this.setFaceUp( ! this.faceUp); }
...
}
Memory Recovery
Because in most languages objects are
dynamically allocated, they must be
recovered at run-time. There are two broad
approaches to this:
Force the programmer to explicitly say when a
value is no longer being used (e.g., C++, Delphi
Pascal):
delete aCard; // C++ example
Use a garbage collection system that will
automatically determine when values are no
longer being used, and recover the memory
(e.g., Java, C#, Smalltalk, CLOS).
Memory Errors
Garbage collection systems impose a run-time
overhead, but prevent a number of potential memory
errors:
Running out of memory because the programmer
forgot to free values
Using a memory value after it has been recovered
PlayingCard * aCard = new PlayingCard(Spade,
delete aCard;
cout << aCard.rank();
Free the same value twice
PlayingCard * aCard = new PlayingCard(Spade, 1);
delete aCard;
delete aCard; // delete already deleted value