views:

233

answers:

6

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. 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. Might there be another way?

Elaboration: I'm writing a raytracer, and each Shape class has a function which returns its bounding box. However, I've made the BBox a subclass of Shape, so I can visualize it. Is this bad design?

+7  A: 

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.

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.

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.

GMan
But then that would require some strange memory management, allocating inside the function and deleting outside it. I guess I could pass a reference to the function though..Elaboration: I'm writing a raytracer, and each Shape class has a function which returns its bounding box. However, I've made the BBox a subclass of Shape, so I can visualize it. Is this bad design?
int3
I answered that, but I would edit your question to give others a chance as well.
GMan
+3  A: 

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:

class Base {
  virtual Base *f() = 0;
};

class Derived : public Base {
  virtual Base *f();
};

Base *Derived::f() {
  Derived *r = new Derived;
  return r;
}
Michael Kohne
+4  A: 

Why not just do:

class Base {
    virtual Base *f() = 0;
};
sylvanaar
+7  A: 

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`.

sbi
doh -- I realize I had put in an empty definition f() into the class declaration, and that was causing the compile errors. I guess this is a case of seeing a nonexistent problem because you expect it to be there.
int3
edit: "into the base class declaration"
int3
@splicer: You can even do this (implementing `Base::f()`). The only caveat is that the implementation must see the definition of `Derived`, so you need to move it out of the class and behind `Derived` (or to `Base.cpp` which includes `Derived.h`, which, from the compiler's POV, is the same).
sbi
+1  A: 

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'.

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*.

quamrana
+2  A: 

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; }
};
luke