0

I have such hierarchy of classes for saving entities found in DXF file:

class MyDxfItem {
   public: DL_Attributes usedAttributes;
   virtual ~MyDxfItem() {}
};
class MyDxfLayer : public MyDxfItem {
    public:
    MyDxfLayer(const std::string& name, int flags, bool off = false): LayerInfo(name,flags,off) {

    }
    public: DL_LayerData LayerInfo;          
};

class MyDxfCircle : public MyDxfItem {

    public: 
        MyDxfCircle(DL_CircleData inCircleInfo): circleInfo(inCircleInfo) {

        }
        
    public: 
    DL_CircleData circleInfo;
};

class MyDxfArc : public MyDxfItem {
    public:
    MyDxfArc(DL_ArcData inArcData) : arcInfo(inArcData) {

    }
    public: DL_ArcData arcInfo;
};
class MyDxfLine: public MyDxfItem {
    public:
        MyDxfLine(DL_LineData inLineData) : lineInfo(inLineData) {

    }
    public: DL_LineData lineInfo;
};
class MyDxfPoint : public MyDxfItem {
    public: DL_PointData pointInfo;
};

class JovanDxfStruct
{
public: std::vector<MyDxfItem> MyListLayers;
public: std::vector<MyDxfItem> MyListItems;
} ;

extern JovanDxfStruct* globalPtrToDxfStruct;

MyDxfLayer is a subclass of MyDxfItem, MyDxfLayer expands and extends MyDxfItem. Base class has virtual destructor. I keep instances of MyDxfLayer in vector: std::vector<MyDxfItem> MyListLayers, it is legal by inheritance.

Here is my code how I add item to this vector:

if (globalPtrToDxfStruct != nullptr) {
        MyDxfLayer layerDataMy(data.name,data.flags, data.off);
        layerDataMy.LayerInfo = data;
        layerDataMy.usedAttributes = attributes;
        globalPtrToDxfStruct->MyListLayers.push_back(layerDataMy);
    }

I create here instance of MyDxfLayer and add it to std::vector. But when I try to downcast it back to its original class I get nullptr:

downcasting not works well

Right after the element was added to array it gets trimmed to baseclass and information stored in instance or derived class seems like lost.

Why is this happening? Why the code:

dynamic_cast<MyDxfLayer*>(&(globalPtrToDxfStruct->MyListLayers[0]))

returns null? you may see that globalPtrToDxfStruct->MyListLayers[0] is not null.

I am adding the instance of derived class to vector of instances of base classes.

I have referenced to example from https://en.wikipedia.org/wiki/Run-time_type_information#dynamic_cast_and_Java_cast , there is an example without vector, but I think it should be similar

Ivan P.
  • 832
  • 2
  • 9
  • 26
  • 1
    `public: std::vector MyListLayers;` -- Two words -- [Object slicing](https://stackoverflow.com/questions/274626/what-is-object-slicing). C++ is not Java. You would want a vector of pointers to the base class, not base class objects. – PaulMcKenzie Jul 07 '20 at 07:24
  • Oh, and once you change to pointers, you have to change your functions to not store stack-based objects in the vector, as you're doing now. Better to have a vector of `unique_ptr` or some other smart pointer. – PaulMcKenzie Jul 07 '20 at 07:29
  • As far as I can remember from classes, if you have created a pointer in subroutine with `new` statement it will be visible and usable in the whole program, until you `delete` it. Easy and useful! `unique_ptr` seems mystic for me... Do I need to `delete` it as well when I do `clear` on vector? Oh, it's another question. I try it, thanks. – Ivan P. Jul 07 '20 at 07:37
  • Yes, you can use `new`, but there is a price to pay, and that is you need to know when and where to call `delete`, else you have memory leaks. Calling `vector` clear will only call the destructor's of the objects in the vector, but since the vector will be one of pointers, no destructor will be called (since pointers do not have a destructor). This is where you have to take the responsibility of calling `delete`. A `std::unique_ptr` will automatically clean up the memory if it is placed in a vector and you call `clear()`. That's why smart pointers are preferred over raw pointers. – PaulMcKenzie Jul 07 '20 at 07:41
  • The bottom line is that C++ is not like C# or Java, where you create a container of a type, and automatically you can put derived types in the container. I believe that in Java, you can cast your way out of it and call `instance of`, but C++ does not work this way. If you want a hierarchy of objects stored in a vector, it needs to be a vector of pointers (of some type) to the base class. Then it's up to you how you want to handle these pointers correctly. – PaulMcKenzie Jul 07 '20 at 07:48

0 Answers0