我有很多东西:
Polygon p1, p2;
我有一个名为Polygon
的{{1}}继承类,我尝试这样做:
Triangle
但由于某种原因,p1 = Triangle(temp1, temp2, temp3); // temp 1,2,3 are lengths of sides
的析构函数在构造结束时被调用。
Triangle
然后它再次运行Rectangle::~Rectangle(void)
{
Polygon::~Polygon();
}
Polygon::~Polygon(void)
{
if (sides != NULL)
{
delete [] sides;
sides = NULL;
}
}
的析构函数。
所以在代码结束后,这是调试器对Polygon
所说的内容(p1
是边数):
n
问题:
p1 {n=3 sides=0x0062c070 {-17891602} } Polygon
和Triangle
的析构函数?编辑: 按要求:
Polygon
另外,感谢解释为什么它运行/*returns true if for the polygons A and B:
(a) for each side on polygon A there is an equal side on polygon B
(b) the number of sides in polygons A and B are equal
(c) sum of sides of A equals the sum of sides of B */
bool Polygon::operator==(const Polygon& p) const
{
if (n != p.n)
return false;
if(circumference() != p.circumference())
return false;
for (int i=0; i < n; i++)
if (!doesSideHasEqual(sides[i], p, n))
return false;
return true;
}
,将考虑到这一点。
答案 0 :(得分:2)
这一行:
p1 = Triangle(temp1, temp2, temp3);
构造一个三角形对象,然后在p1中创建该对象的副本,并销毁原始对象。它是您所看到的原始对象的析构函数。 (它可能不会做你想要的,因为它会切割对象,只存储基类所具有的部分。)
此外,您不应该在析构函数中调用基类的析构函数,它们会自动调用。
作为一种风格问题
if (sides != NULL)
{
delete [] sides;
sides = NULL;
}
在删除之前不需要测试边,因为空指针上的删除在设计上没有任何作用。
表示,在析构函数运行后,对象根本不存在答案 1 :(得分:0)
Polygon p1;
p1 = Triangle(temp1, temp2, temp3); // temp 1,2,3 are lengths of sides
实际上是在给你超出预期的结果。
你想做的事情就像是
Polygon& p1;
Triangle t(temp1, temp2, temp3);
p1 = t;
或
Polygon* p1 = new Triangle(temp1, temp2, temp3);
中的问题
p1 = Triangle(temp1, temp2, temp3);
不仅是Triangle对象是临时的并且在声明之后就被销毁了,但是,更严重的是,从Triangle对象复制到p1这是Polygon,只是复制像Polygon一样。因此,“复制”p1不包含Triangle的任何信息。
另一个问题是你编写析构函数的方式。 C ++中的析构函数是自动链接的(我认为你来自Java背景,我们需要显式调用超类'终结器)
Rectangle::~Rectangle(void)
{
Polygon::~Polygon(); // can be removed
}
因此,您不应该调用Polygon的析构函数。
析构函数的另一个问题是,如果你的类应该被继承(你的Polygon是一个很好的例子),你应该声明你的析构函数是虚拟的。出于背后的原因,搜索“虚拟析构函数”。
答案 2 :(得分:0)
当你还在学习并且其他人回答你的问题时,这里有一些关于C ++编程的指示。
Polygon p1, p2;
这是Polygon类的两个对象。
p1 = Triangle(temp1, temp2, temp3); // temp 1,2,3 are lengths of sides
这构造了类Triangle
的对象,并在p1
上调用赋值运算符以从Triangle
构造它。 Triangle
透明地向上转换为Polygon
并复制构造为p1
,之后Triangle
临时对象将被销毁。
Rectangle::~Rectangle(void)
{
Polygon::~Polygon();
}
这有一个非常重大的错误和一个微妙的“老式人”的事情。
从不需要在代码中提及(void)
;这在大约14年前的C中才是明智的。我们正在做C ++,我们在2013年这样做,所以不要使用(void)
但只使用()
。这已明确表示不允许任何参数。
但主要的问题是你明确地破坏了父母。父母总是被隐含地破坏。这样它们首先被明确地破坏,然后再次被隐含地破坏。永远不要从析构函数中调用析构函数。
Polygon::~Polygon(void)
{
if (sides != NULL)
{
delete [] sides;
sides = NULL;
}
}
这是“防御性编程”的热潮。代码可以多次调用,也可以在半构造的对象上调用,不会崩溃。另一方面,您也不会在软件的其他部分中暴露错误,因此这些错误将持续存在。双 - delete
通常指向共享所有权,并通过扩展指向悬空指针。这将完美掩盖该错误。
要么确定sides
成员确实有值,要么没有。如果它有值,请始终将其删除。为了安全起见,添加一个断言sides != nullptr
或sides != NULL
来预先检查它,这样如果核心文件/堆栈跟踪没有,代码就会崩溃。
如果它没有值,仍然总是删除它。删除对于空指针值是安全的,从而使代码更加清晰。这完全取消了您的支票。允许将其设置为NULL
,这将有助于查找对此Polygon
对象的悬空指针的使用。