You are on page 1of 8

Structure 5: Objects II

This unit extends the discussion of object-oriented programming and introduces splitting
a program into multiple files.

Syntax introduced:
extends, super

There is far more to object-oriented programming than was described in Structure 4


(p. 395). As your programs become longer and your ideas grow more ambitious, the
additional object-oriented programming concepts and techniques discussed in this unit
become important for managing code.

Multiple constructors

A class can have multiple constructors that assign the fields in different ways. Sometimes
it’s beneficial to specify every aspect of an object’s data by assigning parameters to the
fields, but other times it might be appropriate to define only one or a few.
In the next example, one constructor sets the x-coordinate, y-coordinate, and radius,
while the other uses preset values. When the object is created, the program chooses the
constructor to use depending on the number and type of variables specified. At the end
of setup(), the sp1 object is created using the first version of the Spot constructor, and
the sp2 object is created using the second version.

Spot sp1, sp2; 48-01

void setup() {
size(100, 100);
smooth();
noLoop();
// Run the constructore without parameters
sp1 = new Spot();
// Run the constructor with three parameters
sp2 = new Spot(66, 50, 20);
}

void draw() {
sp1.display();
sp2.display();
}

453
class Spot { 48-01
cont.
float x, y, radius;

// First version of the Spot constructor,


// the fields are assigned default values
Spot() {
x = 33;
y = 50;
radius = 8;
}

// Second version of the Spot constructor,


// the fields are assigned with parameters
Spot(float xpos, float ypos, float r) {
x = xpos;
y = ypos;
radius = r;
}

void display() {
ellipse(x, y, radius*2, radius*2);
}
}

Composite objects

An object can include several other objects. Creating such composite objects is a good
way to use the principles of modularity and build higher levels of abstraction. In the
natural world, objects often possess components that operate independently but in
relation to other components. Using a biological analogy, you might create a cell class,
groups of which can be combined into muscle tissue and nervous tissue. These tissues
can be combined into organs, and the organs into an organism. With multiple layers
of abstraction, each step is built from composites of the previous layer. A bicycle class
provides a different sort of example. It could be composed of objects for its frame,
wheels, brakes, drivetrain, etc., and each of these units could be built from other classes.
For example, the drivetrain could be built from objects for the pedals, crankset, and
gears.
The following program combines the Egg class (p. 405) and the Ring class (p. 408)
to create a new class called EggRing. It has one Egg object called ovoid, created in the
constructor, and one Ring object called circle, created at the base of the class. The
transmit() method calls the methods for both classes and resets circle when the
object reaches its maximum size. As in all the examples using classes, the referenced
classes have to be included in the sketch for the project to run.

454 Structure 5: Objects II


// Requires Egg and Ring classes (codes 43-08 and 43-11) 48-02

class EggRing {
Egg ovoid;
Ring circle = new Ring();

EggRing(int x, int y, float t, float sp) {


ovoid = new Egg(x, y, t, sp);
circle.start(x, y - sp/2);
}

void transmit() {
ovoid.wobble();
ovoid.display();
circle.grow();
circle.display();
if (circle.on == false) {
circle.on = true;
}
}
}

When the EggRing class is used in a program, each instance draws an egg to the screen
with one Ring object growing from its center.

// Requires the Egg, Ring, and EggRing classes 48-03

EggRing er1, er2;

void setup() {
size(100, 100);
smooth();
er1 = new EggRing(33, 66, 0.1, 33);
er2 = new EggRing(66, 90, 0.05, 66);
}

void draw() {
background(0);
er1.transmit();
er2.transmit();
}

455 Structure 5: Objects II


Inheritance

A class can be defined using another class as a foundation. In object-oriented


programming terminology, one class can inherit fields and methods from another. An
object that inherits from another is called a subclass, and the object it inherits from is
called a superclass. A subclass extends the superclass. When one class extends another,
all of the methods and fields from the superclass are automatically included in the
subclass. New fields and methods can be added to the subclass to build on the data and
behavior of its superclass. If a method name is repeated within the subclass and has the
same prototype (the same number of parameters with the same data types) as the one
in the superclass, the method in the subclass overrides the other, thereby replacing it.
When a method or field from the superclass is called from within the subclass, the name
is prefaced with the keyword super to let the software know this method or field is a
part of the superclass. The following examples clarify these new terms and concepts.
The Spin class was created to help explain the concept of inheritance. This very
minimal class has fields for setting the x-coordinate, y-coordinate, speed, and angle. It
has one method to update the angle.

class Spin { 48-04

float x, y, speed;
float angle = 0.0;

Spin(float xpos, float ypos, float s) {


x = xpos;
y = ypos;
speed = s;
}

void update() {
angle += speed;
}
}

The SpinArm class inherits elements from Spin and draws a line using the superclass’s
data. The constructor for SpinArm simply calls the constructor of the superclass. The
display() function uses the inherited x, y, angle, and speed fields to draw a rotating
line. Notice that the declarations for these fields are not repeated in the subclass because
they are accessible to the subclass.
In the SpinArm constructor, super() is used to call the constructor of the Spin
superclass. If super() with parameters is not used in the constructor of a subclass, a line
calling super() with no parameters will be inserted behind the scenes. For this reason,
any class meant to be extended will usually require a version of its constructor with no
parameters, except in cases like this example where all subclasses call super() explicitly.

456 Structure 5: Objects II


class SpinArm extends Spin { 48-05

SpinArm(float x, float y, float s) {


super(x, y, s);
}

void display() {
strokeWeight(1);
stroke(0);
pushMatrix();
translate(x, y);
angle += speed;
rotate(angle);
line(0, 0, 100, 0);
popMatrix();
}
}

The SpinSpots class also inherits the elements of Spin. Like the SpinArm class, it
uses its superclass’s fields and constructor, but it builds even further on Spin by adding
another field. The dim field was added to give the option to change the size of the circles.
Notice that this field is declared at the top of the class, assigned in the constructor, and
accessed in the display() method to set the size of the circles.

class SpinSpots extends Spin { 48-06


float dim;

SpinSpots(float x, float y, float s, float d) {


super(x, y, s);
dim = d;
}

void display() {
noStroke();
pushMatrix();
translate(x, y);
angle += speed;
rotate(angle);
ellipse(-dim/2, 0, dim, dim);
ellipse(dim/2, 0, dim, dim);
popMatrix();
}
}

457 Structure 5: Objects II


The process of creating objects from a subclass is identical to that of creating objects
from a normal class. The class is the data type, and object variables of this type are
declared, created, and accessed with the dot operator. In the following program, one
SpinSpot object and one SpinArm object are declared and created. Their update()
methods are used to increment the angle and draw to the screen. The class definitions
for Spin, SpinSpots, and SpinArm must be included in the same page or put in
separate tabs within the same sketch.

// Requires the Spin, SpinSpots, and SpinArms class 48-07

SpinSpots spots;
SpinArm arm;

void setup() {
size(100, 100);
smooth();
arm = new SpinArm(width/2, height/2, 0.01);
spots = new SpinSpots(width/2, height/2, -0.02, 33.0);
}

void draw() {
background(204);
arm.update();
arm.display();
spots.update();
spots.display();
}

The next example extends the Button class (p. 439) introduced in Input 7. The extended
class allows the cursor to move the button to different positions on the screen. This is
one of the primary actions of most computer interfaces. The DragButton class inherits
the behavior of responding to mouse events and extends this with the ability to move
when it is clicked and dragged by the mouse. This subclass uses the existing update()
and display() methods, augments the press() method, and adds a drag() method
to update its position when the mouse is dragged.

class DragButton extends Button { 48-08


int xoff, yoff;

DragButton(int x, int y, int s, color bv, color ov, color pv) {


super(x, y, s, bv, ov, pv);
}

void press(int mx, int my) {

458 Structure 5: Objects II


super.press(); 48-08
cont.
xoff = mx - x;
yoff = my - y;
}

void drag(int mx, int my) {


if (press == true) {
x = mx - xoff;
y = my - yoff;
}
}
}

The following example shows this new DragButton class embedded into a program.
Its methods are run from the mouse event functions to register the status of the mouse
with the icon object.

// Requires DragButton and Button classes 48-09

DragButton icon;

void setup() {
size(100, 100);
smooth();
color gray = color(204);
color white = color(255);
color black = color(0);
icon = new DragButton(21, 42, 50, gray, white, black);
}

void draw() {
background(204);
icon.update(mouseX, mouseY);
icon.display();
}

void mousePressed() { icon.press(mouseX, mouseY); }


void mouseReleased() { icon.release(); }
void mouseDragged() { icon.drag(mouseX, mouseY); }

The DragButton class can be extended further to allow an image to be loaded and
displayed as the icon. This class is very similar to DragButton but adds a field for the
image and completely overrides the display() method to draw an outline around the
image. This action provides visual feedback when the cursor is over the icon and when

459 Structure 5: Objects II


the mouse is over the icon and pressed. Try integrating this new DragImage class into
the previous example.

class DragImage extends DragButton { 48-10


PImage img;

DragImage(int x, int y, int d, String s) {


super(x, y, d, color(204), color(255), color(0));
img = loadImage(s);
}

// Override the display() from Button


void display() {
if (press == true) {
stroke(pressGray);
} else if (over == true) {
stroke(overGray);
} else {
stroke(baseGray);
}
noFill();
rect(x-1, y-1, size+1, size+1);
image(img, x, y, size, size);
}
}

While modular programming is an important technique, it can be too much of a good


thing. Be careful to not abstract your code to a point where it becomes cumbersome. In
the example above, the description of this simple button behavior with three classes
is not practical. It was created this way to demonstrate key concepts of object-oriented
programming, but could (and probably should) be simplified to one or two classes.

Exercises
1. Write another constructor for the Spot class and use it within a variation
of code 48-01.
2. Create your own composite class from two previously existing classes.
3. Create a unique subclass from the Button class.

460 Structure 5: Objects II

You might also like