C++ 覆盖方法

Posted

技术标签:

【中文标题】C++ 覆盖方法【英文标题】:C++ Overriding Methods 【发布时间】:2010-11-16 19:57:18 【问题描述】:

我不知道这是怎么回事。

我有一个 Scene 类,它有一个实体向量,允许您从场景中添加和获取实体:

class Scene 
    private:
        // -- PRIVATE DATA ------
        vector<Entity> entityList;
    public:
        // -- STRUCTORS ---------
        Scene();
        // -- PUBLIC METHODS ----
        void addEntity(Entity); // Add entity to list
        Entity getEntity(int); // Get entity from list
        int entityCount();
;

我的Entity类如下(输出用于测试):

class Entity 
    public:
        virtual void draw()  cout << "No" << endl; ;
;

然后我有一个继承自 Entity 的 Polygon 类:

class Polygon: public Entity

    private:
        // -- PRIVATE DATA ------
        vector<Point2D> vertexList; // List of vertices
    public:
        // -- STRUCTORS ---------
        Polygon() ; // Default constructor
        Polygon(vector<Point2D>); // Declare polygon by points
        // -- PUBLIC METHODS ----
        int vertexCount(); // Return number of vertices
        void addVertex(Point2D); // Add vertex
        void draw()  cout << "Yes" << endl; ; // Draw polygon
        // -- ACCESSORS ---------
        Point2D getVertex(int); // Return vertex
;

如您所见,它有一个 draw() 方法,该方法应该覆盖它从 Entity 类继承的 draw() 方法。

但事实并非如此。使用以下代码时:

scene->getEntity(0).draw();

实体 0 是多边形(或至少应该是),它从父方法打印“否”(好像它不是多边形,只是一个实体)。事实上,它似乎不允许我调用任何 Polygon 独有的方法而不获取:

'一些方法名':不是'Entity'的成员

所以知道发生了什么吗?

感谢您的帮助。

更新:

所以我已经实现了第一个答案中给出的代码,但我不确定如何将我的多边形添加到列表中。像这样?

const tr1::shared_ptr<Entity>& poly = new Polygon;
poly->addVertex(Point2D(100,100));
poly->addVertex(Point2D(100,200));
poly->addVertex(Point2D(200,200));
poly->addVertex(Point2D(200,100));
scene->addEntity(poly);

我只是不习惯这个 shared_ptr 业务。

【问题讨论】:

尝试在场景类中存储指向实体的指针而不是实体对象的副本。 【参考方案1】:

我认为你需要发布你的调用代码,但本质上的问题是这个。

你有一个具体类 Polygon 派生自另一个具体类 Entity。您的 addEntity 和 getEntity 函数采用并返回 Entity 按值 因此,如果您尝试传入或检索 Entity,您将仅复制该对象的 Entity 部分(将其切片) 并且有关对象的派生部分的信息将丢失。

此外,您还有一个Entityvector,它是基类对象的向量,因此除了对象的基类型之外,您无法存储任何其他内容。

如果您需要一个混合类型对象的集合,但所有对象都派生自Entity,您可能需要使用动态创建的对象和某种智能指针,例如tr1::shared_ptrboost::shared_ptr .

例如

class Scene 
    private:
        // -- PRIVATE DATA ------
        vector< std::tr1::shared_ptr<Entity> > entityList;
    public:
        // -- STRUCTORS ---------
        Scene();
        // -- PUBLIC METHODS ----
        void addEntity( const std::tr1::shared_ptr<Entity>& ); // Add entity to list
        const std::tr1::shared_ptr<Entity> getEntity(int); // Get entity from list
        int entityCount();
;

编辑

您更新后的调用代码基本上是正确的,尽管使用对共享指针的本地 const 引用有点晦涩。

我可能会选择类似的东西:

std::tr1::shared_ptr<Polygon> poly( new Polygon );
poly->addVertex(Point2D(100,100));
poly->addVertex(Point2D(100,200));
poly->addVertex(Point2D(200,200));
poly->addVertex(Point2D(200,100));
scene->addEntity(poly);

【讨论】:

或者更形象地说,发布的代码采用 Polygon 并将其放入 Entity 大小的盒子中,但并不完全适合。 现在的问题是 addVertex() 是 Polygon 独有的:错误 C2039: 'addVertex' : is not a member of 'Entity' 感谢您的大力帮助。 (抱歉,我不确定是否应该在 cmets 中发布这些额外的问题) 编辑,好点。在将其添加到场景之前,您应该能够在本地使用 shared_ptr 到 Polygon。它应该隐式转换为 shared_ptr 到实体。我已经进行了适当的编辑。 这种行为在 C++ 中称为切片:***.com/questions/274626#274636【参考方案2】:

chollida 的评论是正确的:您将 Polygon 类型的对象推送到用于 Entity 类型的内存位置,并遇到所谓的 slicing。多余的“多边形”信息被切掉,剩下的就是实体。

在这些情况下,您应该存储指向基类的指针(或引用,如果可能)。

【讨论】:

【参考方案3】:

您应该为此使用纯虚函数。

class Entity

public:
    virtual void draw() = 0;
;

然后从你的对象调用draw函数,你也应该使用指向你的对象的指针。

【讨论】:

> 您应该为此使用纯虚函数。不必要。 Entity 类当然可以有一个具体的 draw 方法。【参考方案4】:

根据经验,在处理打算以多态方式使用的对象时,您应该始终使用引用语义(即通过指针或引用访问对象)而不是值语义。

为了以这种方式确保安全,明智的做法是通过创建私有复制构造函数和赋值运算符来创建所有多态类型的基类noncopyable。这将有效地防止切片,因为如果错误地使用了值语义,代码将无法编译。

【讨论】:

【参考方案5】:

您应该首先存储指向实体实例的指针(最好是智能指针:))。 Vector 在插入时会重新分配,因此即使在调用 getter 方法之前,您的对象也会被切片。

getter 方法的返回类型也应该是指针或引用,这样您就可以进行多态调用。

【讨论】:

以上是关于C++ 覆盖方法的主要内容,如果未能解决你的问题,请参考以下文章

C++ 实现子类扩展子接口而不覆盖已经覆盖的方法

C++ 风格:为覆盖方法添加前缀 virtual 关键字

多继承 C++ 中的覆盖方法

C++ 覆盖继承的方法

C++在终端文件中就地覆盖输出的方法

C++在终端文件中就地覆盖输出的方法