[英]Is it possible to return a derived class from a base class method in C++?
I would like to do this: 我想这样做:
class Derived;
class Base {
virtual Derived f() = 0;
};
class Derived : public Base {
};
Of course this doesn't work since I can't return an incomplete type. 当然这不起作用,因为我不能返回不完整的类型。 But neither can I define Derived before base, since I can't inherit from an incomplete type either.
但是我也不能在base之前定义Derived,因为我也不能从不完整的类型继承。 I figure that I could use templates as a workaround (using Derived as a template argument to Base), but it seems a really ugly way of doing things.
我认为我可以使用模板作为解决方法(使用Derived作为Base的模板参数),但这似乎是一种非常丑陋的做事方式。 Might there be another way?
可能还有另一种方式吗?
Elaboration: I'm writing a raytracer, and each Shape class has a function which returns its bounding box. 详细说明:我正在编写一个光线跟踪器,每个Shape类都有一个返回其边界框的函数。 However, I've made the BBox a subclass of Shape, so I can visualize it.
但是,我已经让BBox成为Shape的子类,所以我可以想象它。 Is this bad design?
这是不好的设计吗?
There's nothing wrong with the code in your question. 您的问题中的代码没有任何问题。 This
这个
class Derived;
class Base {
virtual Derived f() = 0;
};
class Derived : public Base {
virtual Derived f() {return Derived();}
};
should compile just fine. 应该编译得很好。 However, callers of 'Base::f()' will need to have seen the definition of 'Derived`.
但是,'Base :: f()'的调用者需要看到'Derived`的定义 。
You could use a pointer (or a reference): 您可以使用指针(或引用):
class Derived;
class Base {
virtual Derived *f() = 0;
};
class Derived : public Base {
};
But this is code smell to me. 但这对我来说是代码味道。 Why should anybody inheriting from this class need to know about another derived class?
为什么从这个类继承的人需要知道另一个派生类? In fact, why should the base class be concerned with it's derivee's?
事实上,基类为什么要关注它的衍生物呢?
For your situation, you'll need to notice things that mgiht be a signal for bad design. 根据您的情况,您需要注意那些不好的设计信号。 Although it makes sense that your bounding box would derive from
Shape
, keep in mind, since Shape
has a function that returns a bounding box, a bounding box will have a function that returns itself. 虽然你的边界框从
Shape
派生是有意义的,但请记住,因为Shape
有一个函数返回一个边界框,一个边界框将有一个返回自身的函数。
I'm not sure the best solution, but you could make BBox
a separate class altogether, and perhaps give it a function akin to: Shape *as_shape(void) const
, which would construct a class Box : public Shape
with the same dimensions as the bounding box. 我不确定最好的解决方案,但你可以完全将
BBox
作为一个单独的类,并且可能给它一个类似于: Shape *as_shape(void) const
,它将构造一个class Box : public Shape
,其尺寸与边界框。
I still feel there is a better way, but I'm out of time for now, I'm sure someone else will think of a better solution. 我仍然觉得有更好的方法,但我现在没时间了,我相信别人会想到更好的解决方案。
Why not just do: 为什么不这样做:
class Base {
virtual Base *f() = 0;
};
Your notion about templates wasn't necessarily a bad one. 你对模板的看法不一定是坏的。 What you describe is called the Curiously Recurring Template Pattern .
您描述的内容称为奇怪的重复模板模式 。
An example: 一个例子:
#include <iostream>
template <typename T>
struct Base
{
virtual T* foo() = 0;
};
struct Derived : Base<Derived>
{
virtual Derived* foo() { return this; }
};
I'd go with returning a pointer to a Base, so that Base doesn't need to know about Derived or anything else that comes along later: 我将返回指向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;
}
As others have pointed out, the code sample you have can be made to work, but that you probably mean to return a pointer to the base class from f()
. 正如其他人所指出的那样,你可以使你的代码示例工作,但你可能意味着从
f()
返回一个指向基类的指针。
In your elaboration, you mention that the bounding box is a subclass of shape, but there is a problem: 在您的详细说明中,您提到边界框是形状的子类,但是存在一个问题:
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?
};
Lets move some of the responsibilities around: 让我们解决一些责任:
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
};
Your application will now probably need to hold collections of BoundedShape*
and occasionally ask one for its BBox*
. 您的应用程序现在可能需要保存
BoundedShape*
集合,并偶尔询问其中的BBox*
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.