Session 2: Classes in C++

C++ source files

A C++ source file may contain:
include directives #include <iostream>
comments // what this does
constant definitions const double pi = 3.14159;
global variables int count;
function definitions int foo(int x) { ... }
class definitions class Foo { ... };
Unlike Java, C++ requires that things are declared before use.

Classes in C++

The elements of a C++ class

    class Date {
As in Java, C++ classes contain:
    };

Visibility of members and methods

Visibility is indicated by dividing the class into sections introduced by access specifiers:
    class Date {
    private:
        int day, month, year;

    public:
        Date() ...
        Date(int d, int m, int y) ...
        int get_day() { return day; }
        ...
    };
In this case, the fields are private, and the constructors and methods are public.

Access specifiers

C++ has the same keywords as in Java, but as there are no packages, the situation is simpler:
private
visible only in this class.
protected
visible in this class and its descendents.
public
visible in all classes.

Constant member functions

Recall that the const keyword is used for values that cannot be changed once initialized:
        const int days_per_week = 7;
        int last(const vector<int> &v) { ... }
We can indicate that the function get_day() doesn't change the state of the object by changing its declaration to
        int get_day() const { return day; }
This will be checked by the compiler.

Advice: add const where appropriate.

Constructors

Initialization and assignment of objects

Unlike basic types, objects are always initialized.

    Date today;     // uses default constructor
                    // note: no parentheses
    Date christmas(25, 12);
Initialization as a copy of another object:
    Date d1 = today;
    Date d2(today); // equivalent
Assignment of objects performs a copy, member-by-member:
    d1 = christmas;
These are the defaults; later we shall see how these may be overridden.

Using objects

Declaring object variables:

    Date today;
    Date christmas(25, 12);
In C++ (unlike Java) these variables contain objects (not pointers/references to objects) and they are already initialized.

Methods are invoked with a similar syntax to Java:

    cout << today.get_day();
    christmas.set_year(christmas.get_year() + 1);
except that in C++ today is an object.

Qualification in C++ and Java

Java uses dot for all qualification, while C++ has three different syntaxes:

C++ Java
 object.field  (no equivalent)
 pointer->field  reference.field
 Class::field  Class.field
(no equivalent) package.Class

Temporary objects

We can also use the constructor to make an object inside an expression:

    cout << Date().get_day();
An object is created and initialized, the method get_day() is called, and the object is discarded. (You can get a similar effect in Java with new, but this relies on automatic garbage collection.)

Another example:

    Date d;
    ...
    d = Date(25, 12);
An object is created and initialized, copied into d, and then discarded.

Initializing members

Members are initialized by constructors, not in their declarations.

        class Date {
                int day, month, year;
        public:
                Date() : day(current_day()),
                        month(current_month()),
                        year(current_year()) {}

                Date(int d, int m, int y) :
                        day(d), month(m), year(y) {}
                ...
        };

Initializing subobjects

Initializers supply constructor arguments:

        class Event {
                Date when;
                string what;
        public:
                Event(string name) : what(name) {}

                Event(string name, int d, int m) :
                        what(name), when(d, m) {}
                ...
        };
If no initializer is supplied, the default constructor is used.

Two ways to define methods

The Date class minus the method definitions

    class Date {
    private:
        int day, month, year;

    public:
        Date();
        Date(int d, int m);
        Date(int d, int m, int y);

        int get_day() const;
        int get_month() const;
        int get_year() const;
    };
Note that this falls short of an ideal interface, as all members (even private ones) must be included.

The deferred method definitions

At a later point, outside of any class, we can define the methods. To indicate which class they belong to, they are qualified with ``Date::''.

    Date::Date() : day(current_day()),
            month(current_month()),
            year(current_year()) {}

    Date::Date(int d, int m, int y) :
            day(d), month(m), year(y) {}

    int Date::get_day() const { return day; }
Advice: place only the simplest method bodies in the class.

Differences with Java

Assertions (revision)

precondition
a condition that the client must meet in order to call a method.
postcondition
a condition that the method promises to meet, if the precondition was satisfied.
invariant
a condition of the state of the class, which each method must preserve.
Assertions should always be documented. Where possible, they should be checked by the program.

C-style assertions

Next week: Operator overloading