Separating Method Declarations and Definitions

Separating Method Declarations and Definitions

It is common in larger C++ projects to separate a method implementation from its declaration. A simple example illustrates how to do this; consider the class MyClass:

class MyClass {
    public:
        void my_method() const {
            std::cout << "Executing \"my_method\"\n";
        }
};
// File myclass.h
class MyClass {
    public:
        void my_method() const; // Method declaration
};

No body for my_method appears in the declaration of the class MyClass in myclass.h;

// File myclass.cpp
// Include the class declaration
#include "myclass.h"

#include <iostream>
 // Method definition
void MyClass::my_method() const {
    std::cout << "Executing \"my_method\"\n";
}

The class name and scope resolution operator (::) binds the definition of the method to the class to which is belongs

class Point {
    double x;
    double y;
    public:
        Point(double x, double y): x(x), y(y) {}
    double get_x() const {
        return x;
    }
    double get_y() const {
        return y;
    }
    void set_x(double x) {
        this - > x = x;
    }
    void set_y(double y) {
        this - > y = y;
    }
};
class Point {
    double x;
    double y;
    public:
        Point(double x, double y); // No constructor implementation
    double get_x() const; // and no method
    double get_y() const; // implementations
    void set_x(double x);
    void set_y(double y);
};
// Point constructor
Point::Point(double x, double y): x(x), y(y) {}
// Get the x value
double Point::get_x() const {
    return x;
}
// Get the y value
double Point::get_y() const {
    return y;
}
// Set the x value
void Point::set_x(double x) {
    this - > x = x;
}
// Set the y value
void Point::set_y(double v) {
    this - > y = y;
}

A method signature for a method is just like a global function signature, except a method signature includes the class name as well.

• Point::get_x() is the signature for a method of the Point class named get_x() that accepts no parameters.

• Linear Equation::get_x() is the signature for a method of the Linear Equation class named get_x() that accepts no parameters.

#include <iostream>

class Point {
    double x;
    double y;
    public:
        Point(double x, double y): x(x), y(y) {}
    double get_x() const {
        return x;
    }
    double get_y() const {
        return y;
    }
    void set_x(double x) {
        this - > x = x;
    }
    void set_y(double y) {
        this - > y = y;
    }
};
double dist(const Point & pt1,
    const Point & pt2) {
    // Compute distance between pt1 and pt2 and return it
    // This is a function stub; add the actual code later
    return 0.0; // Just return zero for now
}
int main() {
    Point p1(2.5, 6), p2(0.0, 0.0);
    std::cout << dist(p1, p2) << '\n';
}

Here the Point class is very simple, and the constructor and method implementations are obvious.

enum class SignalColor {
    Red, Green, Yellow
};
class Trafficlight {
    private:
        SignalColor color; // The light's current color: Red, Green, or Yellow
    public:
        Trafficlight(SignalColor initial_color);
    void change();
    SignalColor get_color() const;
};

Signal Color is an enumerated type that clients may use. (Section 3.9 introduced enumerated types.) By using an enumerated type, we restrict a traffic light object’s color to the three specified by Signal Color. The traffic signal implementation code in defines the Traffic light methods.

#include "trafficlight.h"
 // Ensures a traffic light object is in the state of
// red, green, or yellow. A rogue value makes the
// traffic light red
Trafficlight::Trafficlight(SignalColor initial_color) {
    switch (initial_color) {
    case SignalColor::Red:
    case SignalColor::Green:
    case SignalColor::Yellow:
        color = initial_color;
        break;
    default:
        color = SignalColor::Red; // Red by default, just in case
    }
}
// Ensures the traffic light's signal sequence
void Trafficlight::change() {
    // Red --> green, green --> yellow, yellow --> red
    if (color == SignalColor::Red)
        color = SignalColor::Green;
    else if (color == SignalColor::Green)
        color = SignalColor::Yellow;
    else if (color == SignalColor::Yellow)
        color = SignalColor::Red;
}
// Returns the light's current color so a client can
// act accordingly
SignalColor Trafficlight::get_color() const {
    return color;
}

If the method definition of Traffic Light::change in traffic light.cpp

Notice that outside the class declaration we must prefix the method names with Traffic Light::. Without this prefix the compiler would treat the identifiers as globals. It would interpret them as free functions, not methods. Signal Color is a global type available to any code that #includes traffic light.h.

#include <iostream>

#include "trafficlight.h"

void print(Trafficlight lt) {
    SignalColor color = lt.get_color();
    std::cout << "+-----+\n";
    std::cout << "| |\n";
    if (color == SignalColor::Red)
        std::cout << "| (R) |\n";
    else
        std::cout << "| ( ) |\n";
    std::cout << "| |\n";
    if (color == SignalColor::Yellow)
        std::cout << "| (Y) |\n";
    else
        std::cout << "| ( ) |\n";
    std::cout << "| |\n";
    if (color == SignalColor::Green)
        std::cout << "| (G) |\n";
    else
        std::cout << "| ( ) |\n";
    std::cout << "| |\n";
    std::cout << "+-----+\n";
}
int main() {
    Trafficlight light(SignalColor::Green);
    while (true) {
        print(light);
        light.change();
        std::cin.get();
    }
}

Observe that the color variable within the Traffic light class is private. This makes it impossible for a client to force a traffic light object to cycle incorrectly;