Home > Enterprise >  C Creating a unique pointer results in error "allocating an object of abstract class type&quo
C Creating a unique pointer results in error "allocating an object of abstract class type&quo

Time:11-01

Edit: Turns out, in my Sunflower implementation, I named the function grow() instead of growImpl() so the compiler didn't find the implementation and was considering Sunflower as abstract. This question can be closed.

I am trying to dynamically create an object of a class which inherits from an interface. I am trying to wrap this object in a unique pointer (I am not allowed to use new) and return it.

I get the following error:

/Library/Developer/CommandLineTools/SDKs/MacOSX12.1.sdk/usr/include/c  /v1/memory:2099:32: error: allocating an object of abstract class type 'Sunflower'
    return unique_ptr<_Tp>(new _Tp(_VSTD::forward<_Args>(__args)...));

The interface has some pure virtual functions. I know that when a function is declared as pure virtual, it must have an implementation. But I have added an implementation just to make it compile. So, I am not sure why Sunflower is considered an abstract class when it is supposed to be an implementation of the Flower interface.

If I remove the virtual and const = 0 keywords from my flower class I get the following error:

/Library/Developer/CommandLineTools/SDKs/MacOSX12.1.sdk/usr/include/c  /v1/memory:2099:32: error: no matching constructor for initialization of 'Sunflower'
    return unique_ptr<_Tp>(new _Tp(_VSTD::forward<_Args>(__args)...));

How do I make sure that sunflower is not considered abstract and create the unique pointer successfully?

This is the flower interface:

#include <algorithm>
#include <numeric>
#include <iostream>
using namespace task3;
std::unique_ptr<Flower>
createSunflower(ex5::task3::Location location, ex5::task3::Color color);

class Flower{
    public:
        Flower();
        
        Flower(Location _location, Color _color) : location(_location.getRow(), _location.getColumn()), color{_color} { }
       
Flower(const Flower&) = delete;
        Flower(Flower&&) = delete;
        virtual ~Flower() = default;

        Flower& operator=(const Flower&) = delete;
        Flower& operator=(Flower&&) = delete;
        ex5::task3::Location getLocation(){return location;}

        void grow(const Garden& garden){
            return growImpl(garden);
        }
        [[nodiscard]] std::unique_ptr<Flower> spread(const Garden& garden){
            return spreadImpl(garden);
        }

        Color getColor(){return color;}

        Location location;
        Color color;
    
    private:
    
        virtual void growImpl(const Garden&) ;
        [[nodiscard]] virtual std::unique_ptr<Flower> spreadImpl(const Garden&) ;
};

       

The implementation of this is here, which contains the sunflower class. The line that is giving me the error is in the function createSunflower(). I just added the make_unique in spread() to provide an implementation. But the line in createSunflower is giving me the error with or without the implementation of spread() and grow() :

using namespace task3;
class Sunflower final: public Flower{
    //public:
    private:
        
        void grow(const Garden& garden) const override{
            cout << endl;
        }
        [[nodiscard]] std::unique_ptr<Flower> spread(const Garden& garden)const override {
            
            return std::make_unique<Flower> ({0,0}, Color::BLACK);
        }
        
    
};
std::unique_ptr<Flower>
createSunflower(ex5::task3::Location location, ex5::task3::Color color){
    
    return std::make_unique<Sunflower>(location, color);
}

The enums and structs are defined here, these are given to me and I cannot change them:

namespace task3{
class Garden {
public:
  plant(){
   //do stuff
  }
private:
     std::vector<std::unique_ptr<Flower>> flowers;
};
class Location {
public:
  Location(size_t row, size_t column)
    : locationPair{row, column}
      { }

  [[nodiscard]] size_t getRow()    const noexcept { return locationPair.first; }
  [[nodiscard]] size_t getColumn() const noexcept { return locationPair.second; }


private:
  std::pair<size_t, size_t> locationPair;
};


enum class Color {
  WHITE, RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET, BLACK
};
}}

CodePudding user response:

std::make_unique<T>() creates an instance of T, which means T can't be an abstract type.

So, inside of Sunflower::spread(), calling std::make_unique<Flower>(...); will not work when Flower is an abstract type. You MUST instantiate a derived class instead in that case, eg

return std::make_unique<Sunflower>(...);

spread() returns a unique_ptr<Flower>. A unique_ptr<Sunflower> can be assigned to a unique_ptr<Flower> as long as Flower has a virtual destructor (which it does in your example).

Just like your createSunflower() function is doing. In fact, you could simply have Sunflower::spread() call createSunflower() instead, eg:

std::unique_ptr<Flower> createSunflower(ex5::task3::Location, ex5::task3::Color);

class Sunflower final: public Flower{
    //public:
    private:
        ...
        [[nodiscard]] std::unique_ptr<Flower> spread(const Garden&) const override {
            return createSunflower({0,0}, Color::BLACK));
        }
};

std::unique_ptr<Flower>
createSunflower(ex5::task3::Location location, ex5::task3::Color color){
    return std::make_unique<Sunflower>(location, color);
}
  • Related