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