CPSC 427a: Object-Oriented Programming

Michael J. Fischer

Lecture 9
September 27, 2012

Visualizing Structure

Visualization Complicated relations among program parts are often easier to understand from diagrams.

The textbook makes liberal use of data structure and other diagrams.

The Unified Modeling Language (UML) is particularly useful for diagramming class relationships in object-oriented programs.

We give two examples here of diagrams that may help one understand the bar graph example that we have been discussing.

Bar graph data structure

PIC

UML Diagram

PIC

Simple Objects

L-values and R-values Programming language designers have long been bothered by the asymmetry of assignment.

   

x = 3 is a legal assignment statement.
3 = x is not legal.

Expressions are treated differently depending on whether they appear on the left or right sides of an assignment statement.

Something that can appear on the left is called an L-value.

Something that can appear on the right is called an R-value.

Intuitively, an L-value is the address of a storage location – some place where a value can be stored.

An R-value is a thing that can be placed in a storage location.

R-values are sometimes called pure data values.

Simple object declaration

The declaration int x = 3; says several things:

  1. All values that can be stored in x have type int.
  2. The name x is bound (when the code is executed) to a storage location adequate to store an int.
  3. The int value 3 is initially placed in x’s storage location.

The L-value of x is the address of the storage location of x.

The R-value of x is the object of type int that is stored in x.

Simple assignment

The assignment statement x = 3; means the following:

  1. Get an L-value from the left hand side (x).
  2. Get an R-value from the right hand side (3).
  3. Put the R value from step 2 into the storage location whose address was obtained from step 1.

Automatic dereferencing

Given

int x = 3;  
int y = 4;

Consider

x = y;

This is processed as before, except what does it mean to get an R-value from y?

Whenever an L-value is presented and an R-value is needed, automatic deferencing occurs.

This means to go the storage location specified by the presented L-value (y) and get its R-value (4).

Then the assignment takes place as before.

Pointers

Pointer values

Pointer creation

Pointer objects

Objects into which pointers can be stored are called (not surprisingly) pointer objects.

A pointer object is no different from any other object except for the types of values that can be stored in it.

Just as we often conflate “integer” and “integer object”, it is easy to confuse “pointer” with “pointer object”.

Pointer assignment

Pointers can be assigned to pointer objects.

Following a pointer

To follow a pointer means to obtain the L-value it references.

Pointer example

int x = 3;  
int y = 4;  
int* p;  
int* q;  
int* r;

p = &x; // p points to x.
*p = 5; // Now x==5.
q = p; // p and q both point to x.
*q = *p + 1;// Now x==6.
  
Common mistake – dangling pointer
*r = x+y; // What’s wrong here?

Pointer declaration syntax

A word of warning

int x, y; is shorthand for int x; int y; but

int* p, q; is not same as int* p, int* q.

Rather, it means int* p; int q;.

For this reason, many authors put the * next to the variable instead of with the type name.

Spacing around the star doesn’t matter, but logically it belongs with the type.

References

Reference types Recall: Given int x, two types are associated with x: an L-value (the reference to x) and an R-value (the type of its values).

C++ exposes this distinction through reference types and declarators.

A reference type is any type T followed by &, i.e., T&.

A reference type is the internal type of an L-value.

Example: Given int x, the name x is bound to an L-value of type int&, whereas the values stored in x have type int

This generalizes to arbitrary types T: If an L-value stores values of type T, then the type of the L-value is T&.

Reference declarators

The syntax T& can be used to declare names, but its meaning is not what one might expect.

   int x = 3;// Ordinary int variable
   int& y = x;// y is an alias for x
   y = 4; // Now x == 4.

The declaration must include an initializer.

The meaning of int& y = x; is that y becomes a name for the L-value x.

Since x is simply the name of an L-value, the effect is to make y an alias for x.

For this to work, the L-value type (int&) of x must match the type declarator (int&) for y, as above.

Use of named references

Named references can be used just like any other variable.

One application is to give names to otherwise unnamed objects.

int axis[101];           // values along a graph axis  
int& first = axis[0]  ;  // give name to first element  
int& last = axis[100];   // give name to last element  
first = -50;  
last = 50;  
 
// use p to scan through the array  
int* p;  
for (p=&first; p!=&last; p++) {...}