【问题标题】:C++ Polymorphism issues. Something to do with _vfptrC++ 多态性问题。与_vfptr有关
【发布时间】:2015-04-11 22:45:44
【问题描述】:

我正在尝试创建一个程序,让用户在屏幕上单击两次,然后根据单击的内容绘制一个矩形。

现在我要做的就是将我的类设置为能够手动正确绘制矩形,而不必担心用户点击的位置。

最终我的程序将能够绘制圆形和三角形之类的东西,所以我决定使用多态性并将每种形状类型(即Rectangle)作为其自己的类,继承自一个名为 Shapes 的类。

然后我有一个名为Game 的类,它包含一个Shapes 对象。

Shapes.h

#ifndef _shapes_h_
#define _shapes_h_
#include <vector>
#include "glut.h"

class Shapes
{
public:
    void DrawAll() const;
    void Add(Shapes * shape);
    virtual void Draw() const {}

protected:   
    std::vector<Shapes *> mShapes;
};

#endif  

Shapes.cpp

#include "Shapes.h"
#include <iostream>

void Shapes::DrawAll() const
{
    int i;
    for (i = 0; i < mShapes.size(); i++)
    {
        mShapes[i]->Draw();
    }
}

void Shapes::Add(Shapes * shape)
{
    mShapes.push_back(shape);
}

矩形.h

#ifndef _rectangle_h_
#define _rectangle_h_
#include "Shapes.h"

class Rectangle : public Shapes
{
public:
    Rectangle(std::vector<int> p1, std::vector<int> p2);
    void Draw() const;

private:
    std::vector<int> mP1;
    std::vector<int> mP2;
};

#endif

矩形.cpp

#include "Rectangle.h"
#include <iostream>

Rectangle::Rectangle(std::vector<int> p1, std::vector<int> p2)
{
    mP1 = p1;
    mP2 = p2;
}


void Rectangle::Draw() const
{
    std::cout << "Draw Me " << std::endl;
    glColor3d(0, 0, 0);

    glBegin(GL_QUADS);
    glVertex2d(mP1[0], mP1[1]);
    glVertex2d(mP2[0], mP1[1]);
    glVertex2d(mP2[0], mP2[1]);
    glVertex2d(mP1[0], mP2[1]);
    glEnd();
}

游戏.h

#ifndef _game_h_
#define _game_h_

#include <vector>
#include "Shapes.h"

class Game
{
public:
    void Click(int x, int y);
    void Draw();

private:    
    Shapes mTest;
};

#endif

下面的第一个 Game.cpp 是以我想要做的方式编码的,但它向我抛出了错误 Unhandled exception at 0x001AF742 in Shapes.exe: 0xC0000005: Access violation reading location 0x00000001. 在查看这个之后,我发现一些 __vfptr 隐藏指针变量(我认为控制虚拟东西)设置为 0 并导致内存问题。

注意,Click() 仅在鼠标被按下时被调用,Draw() 在任何类型的事件发生(即鼠标按下、鼠标释放、按键、按键释放等)时被调用。当鼠标被按下时,两个事件都会被调用,但 Click() 会先被调用。

另外,mTest 是 Shapes 对象的变量。

Game.cpp:不起作用

#include "Game.h"
#include "Rectangle.h"
#include <iostream>

void Game::Click(int x, int y)
{     
    std::vector<int> p1;
    p1.push_back(200);
    p1.push_back(200);

    std::vector<int> p2;
    p2.push_back(250);
    p2.push_back(250);

    Rectangle rect(rp1, rp2);

    Shapes * rectangle = &rect;
    mTest.Add(rectangle);
}

void Game::Draw()
{       
    mTest.DrawAll();
}

然而,让我感到困惑的是,如果我在调用DrawAll() 之前在Draw() 函数内添加一个形状矩形到mTest,它就可以工作。但是,我希望能够根据用户单击的位置创建矩形,而这种方法不允许这样做。

Game.cpp:作品

#include "Game.h"
#include "Rectangle.h"
#include <iostream>

void Game::Click(int x, int y)
{     
}

void Game::Draw()
{
    std::vector<int> p1;
    p1.push_back(200);
    p1.push_back(200);

    std::vector<int> p2;
    p2.push_back(250);
    p2.push_back(250);

    Rectangle rect(rp1, rp2);

    Shapes * rectangle = &rect;
    mTest.Add(rectangle);
    mTest.DrawAll();
}

【问题讨论】:

  • 你在第一个例子中有一个悬空指针,只要Game::Click 返回rect 就不再存在了。
  • 所以你的意思是rectGame::Click 结束时被销毁,所以当我将rectangle 添加到mTest 时,它最终会在函数结束时指向任何内容。我该如何解决这个问题?
  • 使mShapes 成为std::vector&lt;std::unique_ptr&lt;Shapes&gt;&gt;,这将确保该类正确处理形状的生命周期,同时仍然允许它们以多态方式使用。
  • 我从未听说过unique_ptr,但我会试一试。然而,这意味着我需要检查所有代码并对其进行修改以使用uniqure_ptr。这很好,除了在我做Shapes * rectangle = &amp;rect; 时,当我尝试做std::unique_ptr&lt;Shapes&gt; rectangle = &amp;rect; 时,我得到了错误。使用unique_ptr时如何处理这个表达式?
  • 说实话你的设计有点不靠谱,为什么形状既是形状又是容器?如果您绝对想坚持这一点,那么一个快速而肮脏的解决方法是将mTest.Add(rectangle); 替换为mTest.Add(new Rectangle(rp1, rp2));,但这可能会导致异常发生时泄漏。

标签: c++ polymorphism glut shapes vptr


【解决方案1】:

在 Shapes 类中替换

std::vector<Shapes *> mShapes; 

std::vector<std::shared_pointer<Shapes>> mShapes; 

比替换代码

Rectangle rect(rp1, rp2);

Shapes * rectangle = &rect;
mTest.Add(rectangle);

mTest.Add(std::make_shared<Rectangle>(rp1, rp2));

最后替换方法定义

void Shapes::Add(Shapes * shape)

通过

void Shapes::Add(std::shared_ptr<Shapes> shape)

它使您的代码有效。

总结:如果您需要指针,请考虑智能指针(@user657267 提到的 std::unique_ptr 也是智能指针)。您可以在许多地方阅读有关智能指针的信息,herehere。为了更好的设计,不要忘记设计模式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-10
    • 1970-01-01
    相关资源
    最近更新 更多