We have already covered three important types of member functions: constructors, getters, and setters. But when creating a class we will often want to provide other member functions to make the it more useful and useable.
One of the goals for objects is that they encapsulate a particular piece of data - they bundle that data with functions to help work with it. We want to build in as much functionality as is reasonable so that other code can βaskβ the object to perform tasks instead of having to do it themselves.
For example, we might know that lots of other code will want to calculate how far a given
Point is from the origin. Rather than make client code implement that calculation, it would be a good idea to provide a distanceToOrigin function that returns how far away the point is from the origin (0, 0).
class Point {
public:
...
// Method to get distance from 0,0
double distanceToOrigin() {
double x = getX(); //call getX on current point
double y = getY(); //call getY on current point
return sqrt(x * x + y * y);
}
double getX() {
return m_x;
}
double getY() {
return m_y;
}
private:
double m_x, m_y;
};
Notice that in a member function like
distanceToOrigin() we can call another member function like getX() without specifying what Point we want to work with.
Outside of the class, we would have to say something like p1.getX() or p2.getX() to specify what point should do the getX() behavior. But if we have already called p1.distanceToOrigin(), then while executing
distanceToOrigin() it is assumed that we are working with p1 as our βcurrent pointβ. So in the same way that m_x is understood to mean p1.m_x,
getX() is assumed to mean p1.getX():
Although member functions can directly access member variables, and the first version of
distanceToOrigin looks simpler, it can useful to use getters and setters to access member data even in member functions. This way, if we later decide to change the implementation of the class, we have less code to fix.
For instance, imagine we decided to switch to storing the point with polar coordinates. In the first version we would have to rewrite all three shown functions to calculate the x and/or y coordinates from polar coordinates. In the second version, we would have to rewrite getX and getY but then could leave distanceToOrigin alone.
A call to a function does involve a very tiny cost in terms of machine level instructions to be executed. But compilers can often optimize away these costs - there is a good chance that a compiler will turn something like getX() into a direct use of the correct value in memory. For most projects, you are much better off optimizing code for readability and maintainability instead of trying to optimize for low level behavior.
What other functions might we want to add to a Point class? It depends on how we anticipate points will be used. Some possible examples might be a function to shift a point or one to get a string representation of the point: