调用重写函数时发生访问冲突


class Element {
public:
ElementTypes type = DOT;
Element() {}
Element(ElementTypes type) : type(type) {}
virtual void Draw() { return; }
};
class Dot : public Element {
public:
int x, y;
Dot(int x, int y) : x(x), y(y) {}
void Draw() override {
DrawCircle(x, y, 2.f, BLACK);
}
};
class Drawing {
public:
std::vector<Element*> Elements;
void AddDot(Dot& dot) {
Elements.emplace_back(&dot);
}
void Draw() { 
for (auto element : Elements) {
element->Draw();
}
}
};

由于某种原因,在尝试调用element->Draw()时出现崩溃。

Exception thrown at 0x00007FF66DDC1486 in geometry.exe: 0xC0000005: Access violation reading location 0x0000000000000000.

我正在使用函数AddDot向向量添加元素

不使用指向类的指针,Draw函数就是没有被覆盖。

问题确实可能是添加到矢量中的dot在绘制时已不存在。典型的情况是,如果您在函数中初始化Drawing,则使用在离开初始化函数时被破坏的本地对象。

解决该问题的一种方法是确保在Drawing中添加的所有图形都是在具有new的自由石上创建的。你以后仍然需要处理它们的删除。这很容易出错。

一个更好的选择是使用智能指针而不是原始指针。这确保了只要有一些智能指针指向该对象,该对象就会保持活动状态,并且一旦不再使用该对象,就会销毁该对象(提示:使用Drawing的析构函数。此处更改:

class Drawing {
public:
std::vector<shared_ptr<Element>> Elements;
void AddDot(shared_ptr<Element> dot) {
Elements.emplace_back(dot);
}
void Draw() { 
for (auto element : Elements) {
element->Draw();
}
}
};
void init (Drawing&d) {
auto dt1 = make_shared<Dot>(10,30); 
d.AddDot(dt1);
}
int main() {
Drawing d; 
init (d);
d.Draw(); 
}

(在线演示(

优点是可以安全地将AddDot()转换为多态AddElement(),避免为每个可能的形状创建新的添加函数。

另一种方法没有智能指针那么复杂和健壮,但相对容易实现:将传递的点作为参数,并制作一个由Drawing拥有(稍后销毁(的副本。不幸的是,对于您当前的代码,这将是麻烦的,因为您需要为想要添加的Element的每个子类使用不同的函数(因为它们的构造函数可能采用不同的参数,并且您不希望发生对象切片(。因此,您需要为Element提供一个clone()函数,该函数返回一个指向新创建的相同类型的Element的指针(这是原型模式(。

欢迎使用您的第一次访问违规
不要惊慌。:(

Access violation reading location 0x0000000000000000

访问违规+像0x0000(零(这样的位置可能只是nullptr。既然你拿着std::vector<Element*> Elements;这样的东西,它从哪里来可能是可以理解的。

要添加新的Element,您需要实际分配
Dot& dot的使用通过引用将其传递到未知位置,这不是一个好的做法,因为您会很快到达UB(或者更糟的是,堆损坏(。

要分配一个新元素,您需要执行以下操作:

std::vector<Element*> Elements;
Elements.push_back(new Element(/*Params here*/));

由于你的课上实际上没有任何昂贵的价值,你可以按价值持有:

std::vector<Element> Elements

为了简单起见,不要探究为什么它应该是值或指针
将其与Composition相结合,为了矢量的简单性,您可以编写一个绘图:

struct Drawable 
{
Drawable(Entity* toDraw) :ToDraw(toDraw) {}
~Drawable() { if(ToDraw != nullptr) { delete ToDraw; } } 
Entity* ToDraw; 
void Draw(){ ToDraw.Draw(); } 
}
// Vector doesn't hold pointers anymore. 
// Passing Drawable& will not result in Undefined behavior but a copy or a move. 
std::vector<Drawable> toDrawVec; 
toDrawVec.emplace_back(new Dot());
toDrawVec.emplace_back(new Square());
toDrawVec.emplace_back(new Square());

请专注于您的学习,并尝试查找unique_ptrshared_ptrRAII(此处使用的技术(。


虚拟函数在这里不起作用,因为Drawing没有继承Element
我建议制作类似Drawable的东西,这样任何需要绘制的实体都可以继承它。

祝你好运!

相关内容

  • 没有找到相关文章

最新更新