我有以下类定义:
class BaseHandle { /* Lots of things */ };
class VertexHandle : public BaseHandle {
/* Only static members and non-virtual functions, default dtor */ };
class EdgeHandle : public BaseHandle { /* Dito */ };
class FaceHandle : public BaseHandle { /* Dito */ };
所有课程都没有虚拟功能或基础
派生类仅派生自BaseHandle
,不添加任何非静态成员,也不添加非默认成员。
我想将Vertex-
,Edge-
和FaceHandles
保存在同一个向量中:
std::vector<BaseHandle*> handles;
但它不起作用,如果我检索BaseHandle
对象并希望dynamic_cast
它们对派生对象失败,因为这些类不是多态的(这是我的解释也许我是错)。
我怎样才能实现BaseHandles
的公共向量?我应该提一下,我不能改变课堂定义,因为它们是第三方图书馆的一部分。
答案 0 :(得分:6)
您需要在父类中使用虚拟析构函数才能以多态方式使用
class BaseHandle
{
public:
virtual ~BaseHandle();
...
};
这是因为dynamic_cast
适用于RTTI(运行时类型信息),只有当您的类至少有一个虚拟成员函数时才可用
这也可以防止资源泄漏,否则只会破坏实例的父类部分
您可以使用std::vector
std::shared_ptr
,不仅可以通过手动调用new
和delete
来避免内存泄漏,而且智能指针也有一个魔法属性(它存储删除器以根据它的构造方式调用破坏)来解决你的问题:
int main()
{
std::vector<std::shared_ptr<BaseHandle>> shared_vec;
shared_vec.push_back(std::make_shared<VertexHandle>());
} // At the end of scope all destructors are called correctly
如果您无权访问c ++ 11,可以使用boost::shared_ptr
答案 1 :(得分:3)
你可以存储
struct thing
{
enum Type { vertex, edge, face };
Type type;
union
{
VertexHandle * vh;
EdgeHandle * eh;
FaceHandle * fh;
};
};
但它基本上是一团糟...你确定要这么做吗?看起来你在一个数组中存储了多个类型,尽管没有办法以多态方式使用它们,所以实际上有一个很好的理由只有一个数组,而不是三个吗?
答案 2 :(得分:1)
如果从BaseHandle
派生的所有类仅使用来自BaseHandle
的单继承(加上可能从具有普通dtor的空类继承,这些属于空基类优化)并且不添加除了非virtual
函数和static
成员之外的所有内容,以及所有派生类都使用默认的dtor或等效类,您只需static_cast
到目标。
虽然要知道没有办法知道哪些派生类,如果有的话,它实际上是。
答案 3 :(得分:1)
继克雷克的评论之后。您可以创建自己的并行类层次结构,并将每个类型添加为成员&#34;。例如:
class MyBaseHandle {
public:
virtual ~MyBaseHandle(){}
virtual Box getBoundingBox() const = 0;
};
class MyEdgeHandle : public MyBaseHandle {
std::unique_ptr<EdgeHandle> handle_;
public:
MyHandle(std::unique_ptr<EdgeHandle> handle) : handle_(std::move(handle)) {}
Box getBoundingBox() const override;
};
如果你愿意,你可以dynamic_cast
。但我会尽量避免使用dynamic_cast
。在并行类层次结构中添加virtual
方法,以满足您的需要。例如,我已经在基类中添加了virtual getBoundingBox
函数,然后您可以专门针对特定类型的句柄:
Box MyEdgeHandle::getBoundingBox() const {
// Get data from EdgeHandle
auto v1 = handle_->getVertex1();
auto v2 = handle_->getVertex2();
// create box from edge data...
return box;
}