C++ 多态性问题。与 _vfptr 有关
C++ Polymorphism issues. Something to do with _vfptr
我正在尝试创建一个程序,让用户在屏幕上点击两次,然后根据点击的内容绘制一个矩形。
现在我要做的就是设置我的 classes 以便能够正确地手动绘制矩形而不用担心用户点击的位置。
最终我的程序将能够绘制圆形和三角形之类的东西,所以我决定使用多态性并让每个形状类型(即 Rectangle
)成为它自己的 class,继承自 class 称为 Shapes
.
然后我有一个名为 Game
的 class,它包含一个 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);
}
Rectangle.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
Rectangle.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();
}
Game.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()
在任何类型的事件发生时调用(e.i。鼠标按下、鼠标释放、按键、键释放等)按下鼠标时,两个事件都会被调用,但 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
添加一个 Shape Rectangle,它就可以工作。但是,我希望能够根据用户点击的位置创建矩形,而此方法不允许这样做。
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();
}
在形状中 class 替换
std::vector<Shapes *> mShapes;
来自
std::vector<std::shared_pointer<Shapes>> mShapes;
比替换代码
Rectangle rect(rp1, rp2);
Shapes * rectangle = ▭
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也是智能指针)。你可以在很多地方读到智能指针,here and here。为了更好的设计,不要忘记设计模式。
我正在尝试创建一个程序,让用户在屏幕上点击两次,然后根据点击的内容绘制一个矩形。
现在我要做的就是设置我的 classes 以便能够正确地手动绘制矩形而不用担心用户点击的位置。
最终我的程序将能够绘制圆形和三角形之类的东西,所以我决定使用多态性并让每个形状类型(即 Rectangle
)成为它自己的 class,继承自 class 称为 Shapes
.
然后我有一个名为 Game
的 class,它包含一个 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);
}
Rectangle.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
Rectangle.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();
}
Game.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()
在任何类型的事件发生时调用(e.i。鼠标按下、鼠标释放、按键、键释放等)按下鼠标时,两个事件都会被调用,但 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
添加一个 Shape Rectangle,它就可以工作。但是,我希望能够根据用户点击的位置创建矩形,而此方法不允许这样做。
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();
}
在形状中 class 替换
std::vector<Shapes *> mShapes;
来自
std::vector<std::shared_pointer<Shapes>> mShapes;
比替换代码
Rectangle rect(rp1, rp2);
Shapes * rectangle = ▭
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也是智能指针)。你可以在很多地方读到智能指针,here and here。为了更好的设计,不要忘记设计模式。