我想这样做:
class Derived;
class Base {
virtual Derived f() = 0;
};
class Derived : public Base {
};
当然这不起作用,因为我不能返回不完整的类型。但是我也不能在base之前定义Derived,因为我也不能从不完整的类型继承。我认为我可以使用模板作为解决方法(使用Derived作为Base的模板参数),但这似乎是一种非常难看的做事方式。可能还有另一种方式吗?
详细说明:我正在编写一个光线跟踪器,每个Shape类都有一个返回其边界框的函数。但是,我已经让BBox成为Shape的子类,所以我可以想象它。这是一个糟糕的设计吗?
答案 0 :(得分:9)
您的问题中的代码没有任何问题。此
class Derived;
class Base {
virtual Derived f() = 0;
};
class Derived : public Base {
virtual Derived f() {return Derived();}
};
应该编译得很好。但是,'Base :: f()'的调用者需要看到'Derived`的定义。
答案 1 :(得分:8)
您可以使用指针(或引用):
class Derived;
class Base {
virtual Derived *f() = 0;
};
class Derived : public Base {
};
但这对我来说是代码味道。为什么从这个类继承的人需要知道另一个派生类?事实上,基类为什么要关注它的衍生物?
根据您的情况,您需要注意那些不良设计的信号。虽然你的边界框来自Shape
是有意义的,但请记住,因为Shape
有一个返回边界框的函数,边界框将有一个返回自身的函数。
我不确定最佳解决方案,但您可以将BBox
完全单独添加,并为其提供类似于Shape *as_shape(void) const
的函数,它将构建class Box : public Shape
与边界框尺寸相同。
我仍然觉得有更好的方法,但我现在没时间了,我相信其他人会想到更好的解决方案。
答案 2 :(得分:4)
为什么不这样做:
class Base {
virtual Base *f() = 0;
};
答案 3 :(得分:4)
你对模板的看法不一定是坏的。您描述的内容称为Curiously Recurring Template Pattern。
一个例子:
#include <iostream>
template <typename T>
struct Base
{
virtual T* foo() = 0;
};
struct Derived : Base<Derived>
{
virtual Derived* foo() { return this; }
};
答案 4 :(得分:3)
我会返回一个指向Base的指针,因此Base不需要知道Derived或后来出现的任何其他内容:
class Base {
virtual Base *f() = 0;
};
class Derived : public Base {
virtual Base *f();
};
Base *Derived::f() {
Derived *r = new Derived;
return r;
}
答案 5 :(得分:2)
正如其他人所指出的那样,的代码示例可以可以工作,但是你可能想要从f()
返回指向基类的指针。
在你的阐述中,你提到边界框是形状的子类,但是有一个问题:
class Shape{
virtual Shape* getBoundingBox() = 0;
};
class Square: public Shape{
virtual Shape* getBoundingBox();
};
class BBox: public Shape{
virtual Shape* getBoundingBox(); // Whoops! What will BBox return?
};
让我们解决一些责任:
class Shape{
virtual void draw() = 0; // You can draw any shape
};
class BBox: public Shape{
virtual void draw(); // This is how a bounding box is drawn
};
class BoundedShape: public Shape{
virtual BBox* getBoundingBox() = 0; // Most shapes have a bounding box
};
class Square: public BoundedShape{
virtual void draw();
virtual BBox* getBoundingBox(); // This is how Square makes its bounding box
};
您的应用程序现在可能需要保留BoundedShape*
的集合,并偶尔询问其BBox*
。