Reading Effective C++, Item 31 describes two methods for minimizing recompilation time by having clients use one class which only provides an interface to functions they can call. This class refers those function calls to other classes that do the real work.
The first method described is the Handle class, which uses the pImpl idiom to forward function calls to an implementation class, which contains the implementation of everything it's doing. The Handle class has a pointer to an instantiated object of this type, and its functions call the corresponding functions on that object and return their values.
The one I'm having problems with is the second one, where this is implemented using a base class with all pure virtual functions. In this method, the base class defines what functions are allowed to be called, but they are all declared as pure virtual, and so the derived class is what actually implements them. Clients have pointers or references to the base class which point to derived class objects, and call those functions, which map to the derived class' implemented functions. The book describes having the Base class have a factory function which returns a pointer to the derived class. From the book's example, if Person is the base class and RealPerson is the derived class, clients should be able to create an object like this:
std::string name;
Date dateOfBirth;
Address address;
//create an object supporting the Person interface
std::tr1::shared_ptr<Person> pp(Person::create(name, dateOfBirth, address);
When I tried to implement something similar, built around a Rational class, I ran into problems, however:
class Rational;
class RationalBase {
public:
virtual ~RationalBase ();
static RationalBase* create(int top, int bottom) {
RationalBase* ptr = new Rational(top, bottom);
return ptr;
}
virtual int getNumerator () const = 0;
virtual int getDenominator () const = 0;
virtual void setNumerator (int) = 0;
virtual void setDenominator (int) = 0;
};
class Rational : public RationalBase {
public:
Rational (int top, int bottom) : numerator(top), denominator(bottom) {}
virtual ~Rational () {}
virtual int getNumerator () const {
return numerator;
}
virtual int getDenominator () const {
return denominator;
}
virtual void setNumerator (int top) {
numerator = top;
}
virtual void setDenominator (int bottom) {
denominator = bottom;
}
private:
int numerator;
int denominator;
};
The g++ compiler is giving me the error invalid use of incomplete type ‘struct Rational’
on the line RationalBase* ptr = new Rational(top, bottom);
inside the create
function.
Googling this error, I found this question which explains that the reason for this is that you're only allowed to do so much with forward-declared classes, and creating new instances of them is not one of them. But then I don't understand how the Interface class is supposed to be implemented?