代码之家  ›  专栏  ›  技术社区  ›  int3

是否可以从C++中的基类方法返回派生类?

  •  4
  • int3  · 技术社区  · 15 年前

    我想这样做:

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

    当然,这不起作用,因为我不能返回不完整的类型。但我也不能在基之前定义派生,因为我也不能从不完整的类型继承。我认为我可以使用模板作为解决方案(使用派生的模板参数作为基础),但这似乎是一种真正丑陋的做法。还有别的办法吗?

    详细说明:我正在编写一个光线跟踪器,每个形状类都有一个返回其边界框的函数。但是,我已经将bbox设置为形状的一个子类,所以我可以将其可视化。这个设计不好吗?

    6 回复  |  直到 10 年前
        1
  •  9
  •   sbi    15 年前

    你的问题代码没有问题。这个

    class Derived;
    
    class Base {
        virtual Derived f() = 0;
    };
    
    class Derived : public Base {
        virtual Derived f() {return Derived();}
    };
    

    应该编译得很好。但是,“base::f()”的调用方需要看到 定义 “派生”的。

        2
  •  8
  •   GManNickG    15 年前

    您可以使用指针(或引用):

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

    但这对我来说是代码的味道。为什么从这个类继承的任何人都需要知道另一个派生类?实际上,为什么基类应该关注它的派生类?

    对于您的情况,您需要注意到一些事情,它们可能是坏设计的信号。虽然你的边界框可以从 Shape 记住,因为 形状 具有返回边界框的函数,边界框将具有返回自身的函数。

    我不确定最好的解决办法,但你可以 BBox 一个单独的类,可能给它一个类似于: Shape *as_shape(void) const ,它将构造一个 class Box : public Shape 与边界框的尺寸相同。

    我仍然觉得有更好的方法,但我现在没有时间了,我相信其他人会想出更好的解决方案。

        3
  •  4
  •   sylvanaar    15 年前

    为什么不这么做:

    class Base {
        virtual Base *f() = 0;
    };
    
        4
  •  4
  •   sbi    15 年前

    你对模板的看法并不一定是坏的。你所描述的叫做 Curiously Recurring Template Pattern .

    一个例子:

    #include <iostream>
    
    template <typename T>
    struct Base
    {
        virtual T* foo() = 0;
    };
    
    struct Derived : Base<Derived>
    {
        virtual Derived* foo() { return this; }
    };
    
        5
  •  3
  •   Michael Kohne    15 年前

    我会返回一个指向基的指针,这样基就不需要知道派生的或以后出现的任何其他内容:

    class Base {
      virtual Base *f() = 0;
    };
    
    class Derived : public Base {
      virtual Base *f();
    };
    
    Base *Derived::f() {
      Derived *r = new Derived;
      return r;
    }
    
        6
  •  2
  •   quamrana Ryuzaki L    10 年前

    正如其他人指出的,您所拥有的代码示例 可以 可以使用,但您可能想从返回指向基类的指针 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* .