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