您如何看待这段C ++代码:
Polygon* p;
if(shape=="Rectangle")
p = new Rectangle();
else if(shape=="Triangle")
p = new Triangle();
else
exit(EXIT_FAILURE);
其中Rectangle和Triangle派生自基类Polygon。
它背后的想法是我需要使用派生类中的特定方法,而不知道在程序运行之前我需要哪个类。 有没有更好的方法呢?它编译,但我想知道是否调用所选派生类的析构函数,以便正确释放特定变量。
辅助问题:dynamic_cast操作是否涉及数据副本?
谢谢:)
修改
感谢您提供所有这些非常有益的答案。
现在让我们说方法
bool isIsosceles()
在Triangle中实现,但不在Rectangle中实现。
然后立即打电话
p->isIsosceles()
显然会失败。
我的第一个想法是:
声明并实现isIsosceles()作为基类Polygon中的虚方法
virtual bool isIsosceles()
{
cout << "Isosceles means nothing to me." << endl;
exit(EXIT_FAILURE);
}
或在if语句中使用dynamic_cast。
这些选项中的任何一个都是一个好习惯吗?
非常感谢
答案 0 :(得分:2)
使用新的OK隐式向下转换吗?
这里没有“向下倾斜”:这是对多态行为的直接使用。你的Polygon *
是指向基类的指针;构造代码生成一个对象,通过使用虚拟成员函数抽象出实现。
它编译,但我想知道是否调用了所选派生类的析构函数,以便正确释放特定变量。
如果基类中的析构函数是虚拟的(它应该是),通过基类指针释放对象将正确地执行所有操作:
delete p;
有更好的方法吗?
您可以使用std::unique_ptr<Polygon>
自动删除Polygon
对象的过程。当指针超出范围时,使用智能指针会破坏对象。
dynamic_cast
操作是否涉及数据副本?
我假设你在这里没有使用dynamic_cast
,因为Polygon
为所有感兴趣的操作声明了虚拟成员函数。但是,当您执行dynamic_cast
时,不会进行数据复制。系统检查是否允许强制转换,并为您提供正确的强制转换指针,或返回nullptr
。
答案 1 :(得分:1)
如果您记得delete p
并且Polygon
的析构函数为virtual
,则会有效。这很重要。
更好的选择是将其包装在智能指针中。
答案 2 :(得分:0)
这不是向下倾斜。你实际上在这里使用多态,即创建一些你将用作基类型对象的派生类型的对象。
您可以这样做,但与使用new分配的所有内容一样,请使用delete。另外需要注意的是,您需要在Polygon
中使用虚拟析构函数,如下所示:
class Polygon {
virtual ~Polygon();
}
否则你最终会得到对象切片,也就是你会有“半删除”的对象。
附加说明:仅供参考,使用您的课程,向下转换将执行以下操作:
Polygon* polygon = new Triangle();
Triangle* triangle = dynamic_cast<Triangle*>(polygon);
// Check that we effectively had a triangle under this polygon pointer
if(triangle){
//do something with the triangle
}
答案 3 :(得分:0)
它背后的想法是我需要使用派生类中的特定方法,而不知道在程序运行之前我需要哪个类。
这种方法违背了多态的目的,它允许你在不知道你正在使用的派生类型的情况下执行操作。
有更好的方法吗?
这取决于你最初想要实现的目标。例如,您展示的内容可以作为类工厂的一部分实现。你创建它们之前没有展示过如何使用这些对象,所以很难说你是否做得对不对。
我想知道是否调用了所选派生类的析构函数,以便正确释放特定变量。
仅当~Polygon()
声明为virtual
时才会这样。
dynamic_cast操作是否涉及数据副本?
没有。 dynamic_cast
只是执行运行时查找以获取指向同一对象的VMT的不同部分的指针。