I read about the following way of implementing virtual interfaces in Exceptional C++ Style, but I only really realised the need for it this evening.
Suppose I have a class like this:
class Object
{
public:
virtual void translate (Vector d) = 0;
};
Other classes will inherit from Object, and they will override translate() as necesssary.
class Ball : public Object
{
private:
Vector m_position;
public:
virtual void translate (Vector d)
{
m_position += d;
}
};
Now, suppose later on I decide that I want to keep track of the last time an Object was moved. I might add a variable to store the time of the last movement. I can then set this variable to be the current time in Object::translate().
class Object
{
private:
float m_timeOfLastMove;
public:
virtual void translate (Vector d)
{
m_timeOfLastMove = getCurrentTimeFromSomewhere();
}
};
Now, because translate() was abstract, every other class that I have derived from Object has implemented its own custom implementation of translate(). I now need to go through all my code, and add a call to Object::translate() in each implementation of translate().
class Ball : public Object
{
private:
Vector m_position;
public:
virtual void translate (Vector d)
{
Object::translate(d);
m_position += d;
}
};
This involes a lot of copying and pasting of code, and I end up with calls to Object::translate(d) all over my code. If I forget to add one of these, the compiler will not complain. If I derive a new class from Object later on, and forget to add this call to the base implementation, I have created a new bug also. The bug will likely not lead to a crash immediately, as I am not doing anything particularily dangerous by not calling the base implementation of translate() in this case. If the bug does not lead to a crash, I might not know that the bug exists for some time.
If I had seperated the implementation of translate() from the public interface right from the start, the code would have been more flexible.
class Object
{
private:
virtual void translateImplementation (Vector d) = 0;
public:
void translate (Vector d)
{
translateImplemenentation(d);
}
};
The Object class now has two contracts: Any Object can be translated by calling Object::translate(), and any class that derives from Object must implement translateImplementation(). I am free to change one of these without affecting the other. For example, I could rename the translate() function to move(), and I would not have to change any class the derives from Object.
Suppose I wanted to allow for rotation in the movement of Objects. I could change translateImplementation(Vector d) to transformImplementation(Matrix m).
class Object
{
private:
virtual void transformImplementation (Matrix m) = 0;
public:
void translate (Vector d)
{
Matrix m;
m.translation = d;
transformImplementation(m);
}
void transform (Matrix m)
{
transformImplementation(m);
}
};
All classes that derive from Object would have to change their implementation of translateImplementation(), but all code that calls Object::translate() would not have to be to changed. I can keep the existing translate() function, but also add a transform() function.
The fact that I have made translateImplementation() private is very important. If any other code wants to translate an instance of Object, it must call Object::translate(). It is illegal for any code to call translateImplementation() directly.
Now if I want to go back and modify translate(), it is much easier for me. I may want to add some profiling or logging to all calls to translate(), or I might want to impose some pre-conditions or post-conditions. I can be confident that any additions to the translate() function will not be bypassed by some other class which derived from Object.