阅读 Effective C ++ ,第31项描述了两种方法,通过让客户端使用一个只为其可以调用的函数提供接口的类来最小化重新编译时间。该类将这些函数调用引用到执行实际工作的其他类。
描述的第一个方法是Handle类,它使用pImpl惯用法将函数调用转发给实现类,该实现类包含它所做的所有事情的实现。 Handle类有一个指向这种类型的实例化对象的指针,它的函数调用该对象上的相应函数并返回它们的值。
我遇到问题的是第二个,这是使用具有所有纯虚函数的基类实现的。在此方法中,基类定义允许调用哪些函数,但它们都被声明为纯虚拟,因此派生类实际上是实现它们的。客户端具有指向派生类对象的基类的指针或引用,并调用这些函数,这些函数映射到派生类'实施的功能。本书描述了Base类有一个工厂函数,它返回一个指向派生类的指针。从本书的示例中,如果Person是基类而RealPerson是派生类,则客户端应该能够创建如下对象:
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);
当我尝试实现类似的东西,围绕Rational类构建时,我遇到了问题,但是:
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;
};
g ++编译器在invalid use of incomplete type ‘struct Rational’
函数内的RationalBase* ptr = new Rational(top, bottom);
行上给出了错误create
。
谷歌搜索这个错误,我发现this question解释了这个原因是你只允许用前向声明的类做这么多,并且创建它们的新实例不是他们。但后来我不明白接口类应该如何实现?
答案 0 :(得分:3)
是的,在定义RationalBase* ptr = new Rational(top, bottom);
之前你不能Rational
,因为编译器还不知道那个类型是什么。 (它不知道要分配多少空间,或者还要调用什么构造函数)。就个人而言,我不会使用工厂方法。
我只想让用户写:
RationalBase* ptr = new Rational(top, bottom);
他们自己因为这会使事情变得相当明显。
如果你想使用智能指针,那么他们当然可以写出来。
std::shared_ptr<RationalBase> ptr(new Rational(top, bottom));
std::unique_ptr<RationalBase> ptr(new Rational(top, bottom)); // ensure only one pointer to this object
或更好的在c ++ 11中: - )
auto ptr = std::make_shared<Rational>(top, bottom); // C++11
auto ptr = std::make_unique<Rational>(top, bottom); // C++14 only
如果你真的想使用工厂,那么你可以稍微改变一下事物的顺序并将创建功能移到底部:
class Rational;
class RationalBase {
public:
virtual ~RationalBase () {} // you needed to provide a body to this function
static RationalBase* create(int top, int bottom);
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;
};
// note that this is defined AFTER the Rational class
RationalBase* RationalBase::create(int top, int bottom) {
RationalBase* ptr = new Rational(top, bottom);
return ptr;
}
我假设您知道您可以提供与其声明分开的功能主体。这样做可以解决这些类型的定义顺序&#34;问题。