Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Base class of non polymorphic derived classes

Tags:

c++

I have the following class definitions:

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

All classes have no virtual functions or bases.
The derived classes only derive from BaseHandle and do not add any non-static members, nor non-default dtors.

I want to save Vertex-, Edge- and FaceHandles in the same vector:

std::vector<BaseHandle*> handles;

But it doesn't work, if I retrieve the BaseHandle object and want to dynamic_cast them to the derived object it fails, because the classes are not polymorphic (that's my explanation perhaps I'm wrong).

How could I achieve a common vector of BaseHandles? I should mention, that I can't change the class defintions because they are part of a third party library.

like image 846
TerenceChill Avatar asked Dec 04 '14 10:12

TerenceChill


Video Answer


2 Answers

You need to have a virtual destructor in your parent class for it to be used polymorphically

class BaseHandle 
{
  public:
    virtual ~BaseHandle();

  ...

};

That's because dynamic_cast works with the RTTI (RunTime Type Information) which is only available if your class has at least one virtual member function

And this will also prevent resource leaks, otherwise only the parent class part of your instance would be destroyed


Workaround

You can use an std::vector of std::shared_ptr, not only will you avoid memory leaks by not having to call new and delete by hand but that smart pointer also has a magic property (it stores the deleter to call on destruction based on the way it was constructed) that solves your problem:

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

If you don't have access to c++11 you could use boost::shared_ptr

like image 136
Drax Avatar answered Oct 20 '22 18:10

Drax


You could store

struct thing
{
    enum Type { vertex, edge, face };
    Type type;
    union
    {
        VertexHandle * vh;
        EdgeHandle * eh;
        FaceHandle * fh;
    };
};

but it's basically a mess ... are you sure you want to do this? It looks like you are storing multiple types in a single array despite the fact that there is no way to use them polymorphically, so is there actually a good reason to have only one array, and not three?

like image 3
Andy Newman Avatar answered Oct 20 '22 18:10

Andy Newman