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;