非多态派生类的基类

时间:2014-12-04 10:40:57

标签: c++

我有以下类定义:

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的公共向量?我应该提一下,我不能改变课堂定义,因为它们是第三方图书馆的一部分。

4 个答案:

答案 0 :(得分:6)

您需要在父类中使用虚拟析构函数才能以多态方式使用

class BaseHandle 
{
  public:
    virtual ~BaseHandle();

  ...

};

这是因为dynamic_cast适用于RTTI(运行时类型信息),只有当您的类至少有一个虚拟成员函数时才可用

这也可以防止资源泄漏,否则只会破坏实例的父类部分


解决方法

您可以使用std::vector std::shared_ptr,不仅可以通过手动调用newdelete来避免内存泄漏,而且智能指针也有一个魔法属性(它存储删除器以根据它的构造方式调用破坏)来解决你的问题:

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;
} 

Live demo