OOP: Objected-oriented Programming

In these notes you will learn:

  • How to write a simple class.
  • How to write and use a constructor.
  • How to add functions to a class.

Introduction

Object-oriented programming (OOP) is a popular style of programming supported by most modern programming languages.

OOP works well in graphics and animation. The idea is that every animated thing on the screen has a corresponding object in the program. This approach makes many programs simpler and more flexible.

What we will do here is design a number of simple but useful classes that help us write programs for graphics and animation.

Point Objects

The best way to understand OOP is through an example. Suppose we want to (x, y) points as objects. Here’s how we’ve been doing it without OOP:

float cat_x;
float cat_y;

float dog_x;
float dog_y;

These are two sets of points (cat_x, cat_y) and (dog_x, dog_y).

The OOP approach is different. The idea is to think about points as being their own individual objects. To create an object, we must create a class that describes the object. Here is a class called Point:

class Point {
  float x;
  float y;
}

As you can see, the Point groups that x and y values for the Point together. We can now create points like this:

Point cat = new Point();
Point dog = new Point();

These two lines of code show one of the big advantages of OOP: readability. It is easy to see that cat and dog describe points because we explicitly say that they are of type Point.

Each Point object contains its own copy of x and y, and we access them using dot notation:

println(cat.x + ", " + cat.y);
println(dog.x + ", " + dog.y);

Clearly, cat.x refers to the x value of the cat object, while dog.x refers to the x value of the dog object.

We can also assign values to variables inside a Point object, e.g.:

Point p = new Point();  // (0, 0) by default
p.x = 4;
p.y = 3;
println(p.x + ", " + p.y);  // 4, 3

Whenever you create an object, you use the new operator:

Point bird = new Point();

Every time the expression new Point() is called, a brand new Point object — with its own personal x and y is created.

Constructors

To create an object, you must call one of its constructors. If you don’t create a constructor in the class then Processing automatically creates a default constructor that that does not take any input:

class Point {
  float x;
  float y;

  // no constructor, so Processing automatically
  // creates a default constructor called Point()
}

The only way we can create a Point with this class is by calling its default constructor, e.g.:

Point origin = new Point();

It’s often convenient to initialize a Point to some value other than (0, 0), and so we can add our constructor:

class Point {
  float x;
  float y;

  // constructor
  Point(float x_init, float y_init) {
    x = x_init;
    y = y_init;
  }
}

Now we can write code like this:

Point middle = new Point(250, 250);
println(middle.x + ", " + middle.y);  // 250, 250

There are a couple of important things to note about constructors:

  • The job of a constructor is to assign initialize the object, which usually means assigning initial values to all the variables in the object.

  • A constructor must always have the same name as the class it is within, e.g. a constructor for the Point class must be called Point.

  • A constructor does not have a return type, not even void.

  • We named the inputs to the constructor x_init and y_init to avoid confusion with the x and y variables defined within the Point class. Imagine if we had done this instead:

    Point(float x, float y) {
       x = x;
       y = y;
    }
    

    In the statement x = x, Processing has no way of knowing if an x refers to the one declared on the constructor’s input list, or the one declared earlier in the class. So it assumes that x refers to the x from the constructor’s input list, and so the x in the object never gets changed.

Printing a Point

In the previous examples we often printed the value of a Point to the screen, e.g.:

Point p = new Point(7, -8);
println(p.x + ", " + p.y);  // 7, -8

This is useful, but tedious to type out each time. So lets add a display() function inside the Point class that does this for us:

class Point {
  float x;
  float y;

  Point(float x_init, float y_init) {
    x = x_init;
    y = y_init;
  }

  void display() {
    println("(" + x + ", " + y + ")");
  }
}

Now we can write code like this:

Point cat = new Point(4, 7);
Point dog = new Point(2, 1);

cat.display();  // (4, 7)
dog.display();  // (2, 1)

Adding a Render Function

Finally, lets add simple rendering function that will draw a small red circle centered at the point:

class Point {
  float x;
  float y;

  Point(float x_init, float y_init) {
    x = x_init;
    y = y_init;
  }

  void display() {
    println("(" + x + ", " + y + ")");
  }

  void render() {
    fill(255, 0, 0);
    ellipse(x, y, 10, 10);
  }
}

Here’s a sample program that draws a point wherever the mouse pointer is:

Point pointer;

void setup() {
  size(500, 500);
  smooth();
  noCursor(); // turn off regular pointer
  pointer = new Point(-100, -100);  // start off screen
}

void draw() {
  background(255);
  pointer.render();
  pointer.x = mouseX;
  pointer.y = mouseY;
}

Questions

  1. What does OOP stand for?
  2. Describe, in English, the difference between a class and an object.
  3. Describe, in English, the purpose of a constructor.
  4. What is a default constructor?
  5. What is the return type of a constructor?
  6. Using the last definition of Point from the notes, write a line of Processing code that creates new Point variable named city that is initialized to (55, 33), and then print it to the console.