【问题标题】:C++ Overridden method not getting calledC ++覆盖的方法没有被调用
【发布时间】:2010-11-29 11:08:55
【问题描述】:

形状.h

namespace Graphics {
    class Shape {
    public:
        virtual void Render(Point point) {};
    };
}

矩形.h

namespace Graphics {
    class Rect : public Shape {
    public:
        Rect(float x, float y);
        Rect();
        void setSize(float x, float y);
        virtual void Render(Point point);

    private:
        float sizeX;
        float sizeY;
    };
}

struct ShapePointPair {
    Shape shape;
    Point location;
};

这样使用:

std::vector<Graphics::ShapePointPair> theShapes = theSurface.getList();

for(int i = 0; i < theShapes.size(); i++) {
    theShapes[i].shape.Render(theShapes[i].location);
}

此代码最终调用 Shape::Render 而不是 Rect::Render

我假设这是因为它将Rect 转换为Shape,但我不知道如何阻止它这样做。我试图让每个形状通过覆盖Render 方法来控制它的呈现方式。

关于如何实现这一点的任何想法?

【问题讨论】:

  • 也许您想向我们展示创建矢量元素的代码?
  • 问题和解决方案与stackoverflow.com/questions/1230006这个问题几乎相同。在那里,您有一个(包含一个)具体基类的向量,如果您希望调用 Rect::Render,则必须通过 slicing 派生类创建该向量。

标签: c++ inheritance virtual overriding


【解决方案1】:

由于我的英语很差,我不能很好地解释。

我认为你应该使用引用或指针类型。 因为形状完全定义了它必须做什么。

如果您直接使用您的代码,您的孩子会尝试复制并完成形状的工作。 这就是为什么你的覆盖功能不起作用的原因。

使用指针或引用 像这样。

指针.h

class Parent {
public:
    virtual void work() { printf("parent is working now\n"); }
};
class Child1 {
public:
    virtual void work() { printf("child1 is working now\n"); }
};
class Child2 {
public:
    virtual void work() { printf("child2 is working now\n"); }
};
struct Holder {
    Parent* obj1;
    Parent* obj2;
};
int main() {
    Child1 child1;
    Child2 child2;
    Holder holder = { &child1, &child2 };
    holder.obj1->work();
    holder.obj2->work();
    return 0;
}

reference.h

class Parent {
public:
    virtual void work() { printf("parent is working now\n"); }
};
class Child1 {
public:
    virtual void work() { printf("child1 is working now\n"); }
};
class Child2 {
public:
    virtual void work() { printf("child2 is working now\n"); }
};
struct Holder {
    Parent& obj1;
    Parent& obj2;
};
int main() {
    Child1 child1;
    Child2 child2;
    Holder holder = { child1, child2 };
    holder.obj1.work();
    holder.obj2.work();
    return 0;
}

*ps:我个人使用抽象函数(virtual void something() = 0;)。 因为我有时也忘记了它,所以我把它当作语法错误。

【讨论】:

    【解决方案2】:

    【讨论】:

      【解决方案3】:

      不,这不是强制转换。

      您可以改为存储对基类 Point 的引用:

      struct ShapePointPair {
              Shape shape;
              Point &location;
      };
      

      此引用必须在构造时设置 形状点对。为此添加一个构造函数到 ShapePointPair 目的。它必须通过(新创建的)实例 矩形。

      还要遵守内存管理职责(正确 写析构函数等)。

      【讨论】:

        【解决方案4】:

        您正在直接访问形状对象以使覆盖工作您需要通过指针或引用访问该对象。

        例如,当您将 Shape 分配给 ShapePointPair 时,代码将“切片”对象并且仅将 Shape 位复制到 ShapePointPair

        这样做意味着你必须观察内存管理——所以你可以在结构中使用智能指针 形状点对 { smart_pointer 形状; 点位; };

        【讨论】:

          【解决方案5】:

          问题在于,在您的向量中,您存储的是 Shape 对象的副本,而复制 Shape 对象并不会复制其派生类的数据或功能 - 您已经远离了 slicing 多态性。

          使用 new 和 delete 管理对象,并安排你的向量存储指向它们的指针。

          【讨论】:

            【解决方案6】:

            此问题称为切片 - 复制到基础时会丢失派生功能。 为了避免这种情况,使用指向基类的指针,即

            std::vector<Graphics::Shape*> s;
            s.push_back(&some_rect);
            

            【讨论】:

            • 谢谢。我以前没听说过切片,下次会记住这一点。
            【解决方案7】:

            这是你的问题:

            struct ShapePointPair {
                    Shape shape;
                    Point location;
            };
            

            您正在存储Shape。您应该存储 Shape *shared_ptr&lt;Shape&gt; 或其他内容。但不是Shape; C++ 不是 Java。

            当您将Rect 分配给Shape 时,只会复制Shape 部分(这是对象切片)。

            【讨论】:

            • auto_ptr 将丢失数据,因为 ShapePointPair 在向量中被复制
            • 谢谢。我一直希望在没有指针的情况下做到这一点,因为形状不使用太多内存,所以很容易在堆栈上复制,但这似乎是不可能的。感谢大家的快速回复。
            【解决方案8】:

            多态性仅适用于指向形状的指针,而不适用于形状对象。

            【讨论】:

              猜你喜欢
              • 2011-12-13
              • 1970-01-01
              • 1970-01-01
              • 2015-04-08
              • 2014-05-22
              • 1970-01-01
              • 2017-06-28
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多