Smoggie Tom
Smoggie Tom

Reputation: 312

Can a std::vector of std::shared_ptr hold pointers to different subclasses of the same base class?

I have been attempting to create a dynamic data structure to hold a number of objects of different classes, all of which derive from the same base class. I have found advice in may places that this can be done with a vector of shared pointers. However I cannot get this to work. Code is as follows:

class ElementDetail
{
public:
    virtual void* getData() = 0;

};

class TypecodeDetail : ElementDetail
{
public:
    TypecodeDetail(uint32_t typecode) : _typeCode(typecode) {}

    void* getData();

private:
    uint32_t _typeCode{};
};

int main()
{
    std::vector<std::shared_ptr<ElementDetail>> details;
    details.push_back(std::make_shared<TypecodeDetail>());
}

This gives an error on push_back:

Error (active) E0304 no instance of overloaded function matches the argument list argument types are: (std::shared_ptr<TypecodeDetail>) object type is: std::vector<std::shared_ptr<ElementDetail>, std::allocator<std::shared_ptr<ElementDetail>>>

I have literally copied this code from answers to a number of similar questions that I searched, yet it does not work. Can anyone tell me why? Is what I am attempting possible?

Upvotes: -2

Views: 127

Answers (3)

edrezen
edrezen

Reputation: 1845

To answer your question: yes, it is possible (and advisable not to use new/delete).

There are several issues with your code:

  1. You need public inheritance (by telling nothing to the compiler, private inheritance will be used)
  2. You invoke the default constructor of TypecodeDetail by calling std::make_shared<TypecodeDetail>(). However, as you defined a constructor taking an integer, there is no default constructor generated by the compiler. So, either you call the constructor with an integer value, or you have to define the default constructor (for instance with TypecodeDetail() = default;)

Try this:

#include <cstdint>
#include <vector>
#include <memory>

class ElementDetail
{
public:
    virtual void* getData() = 0;

};

class TypecodeDetail : public ElementDetail
{
public:
    TypecodeDetail(uint32_t typecode) : _typeCode(typecode) {}

    void* getData() { return nullptr; } 

private:
    uint32_t _typeCode{};
};

int main()
{
    std::vector<std::shared_ptr<ElementDetail>> details;
    details.push_back(std::make_shared<TypecodeDetail>(35));
}

Upvotes: 5

Smoggie Tom
Smoggie Tom

Reputation: 312

Solved in comments. If anyone else is struggling, the issue is that class inheritance is private by default and needs to be made explicitly public. So in this case:

class TypecodeDetail : ElementDetail

should have been

class TypecodeDetail : public ElementDetail

Upvotes: 0

Some programmer dude
Some programmer dude

Reputation: 409422

The smart pointers are mimicking actual pointers in almost all ways. Including handling polymorphism through pointers to a base class.

So to answer your question: Yes, that will work.

The error you get is because you try to default-construct a TypecodeDetail object, which doesn't have a default constructor. You need to pass the argument needed by the TypecodeDetail constructor:

details.push_back(std::make_shared<TypecodeDetail>(123));  // For example

There are also other problems, as mentioned in the comments. The private inheritance being the main one.

Upvotes: 2

Related Questions