patterncppMinor
Concept based polymorphism
Viewed 0 times
conceptpolymorphismbased
Problem
I have a concept based polymorphism example listed below. I allow the user to provide any type that implements the draw method and then I add it into a vector of
unique_ptr to concept base. If I have a pointer or reference I want to be able to deal with that even though the solution has value semantics in mind. I thus created a wrapper type which forwards to the correct implementation. I am hoping to get some feedback on if this is the best way to deal with the issue at hand.#include
#include
#include
#include
class drawable_concept{
public:
drawable_concept() = default;
virtual ~drawable_concept() = default;
drawable_concept(drawable_concept const&) = delete;
drawable_concept& operator = (drawable_concept const& ) = delete;
virtual void draw() = 0;
};
template
class drawable_model : public drawable_concept{
public:
typedef T model_type;
drawable_model(T const& model) : model_(model){}
void draw(){
model_.draw();
}
~drawable_model() = default;
private:
T model_;
};
template
class drawable_forwarder{
public:
drawable_forwarder(T const& item) : item_(item){}
inline void draw(){
item_->draw();
}
private:
T item_;
};
class graphics_surface{
public:
void render(){
std::for_each(std::begin(controls_), std::end(controls_), [] (std::unique_ptr const& control){
control->draw();
});
}
template
void push_back(T control){
auto t = new drawable_model(std::move(control));
controls_.push_back(std::unique_ptr(t));
}
private:
std::vector> controls_;
};
struct triangle{
void draw(){
std::cout ptr(new triangle);
drawable_forwarder> fwd(ptr);
surface.push_back(fwd);
surface.render();
return 0;
}Solution
There is not much to be said actually, the concept-based polymorphism seems to be well implemented. You can slightly improve your
Also, I suppose that a
You could also be more consistent with the way you use
One fun addition would be to write a method that would create the
And the following method to
Then, you could use it this way:
push_back method by having it emplace_back the std::unique_ptr. It will be a little bit less verbose:template
void push_back(T control){
auto t = new drawable_model(std::move(control));
controls_.emplace_back(t);
}Also, I suppose that a
draw shouldn't alter the object being drawn. Therefore, you better const-qualify all of your draw methods.You could also be more consistent with the way you use
inline: you inlined drawable_forwarder's draw method but not drawable_model while it basically does the same thing.One fun addition would be to write a method that would create the
drawable_model object in-place. That would require to add the following constructor to drawable_model:template
drawable_model(Args&&... args):
model_(std::forward(args)...)
{}And the following method to
graphics_surface (not sure about the name):template
void emplace_back(Args&&... args)
{
auto t = new drawable_model(std::forward(args)...);
controls_.emplace_back(t);
}Then, you could use it this way:
int main()
{
graphics_surface surface;
// Assume triangle and rectangle have complete constructors
surface.emplace_back(3.5, 6.8, 4.8, 3.2);
surface.emplace_back(/* whatever */);
surface.render();
}Code Snippets
template<class T>
void push_back(T control){
auto t = new drawable_model<T>(std::move(control));
controls_.emplace_back(t);
}template<typename... Args>
drawable_model(Args&&... args):
model_(std::forward<Args>(args)...)
{}template<typename T, typename... Args>
void emplace_back(Args&&... args)
{
auto t = new drawable_model<T>(std::forward<Args>(args)...);
controls_.emplace_back(t);
}int main()
{
graphics_surface surface;
// Assume triangle and rectangle have complete constructors
surface.emplace_back<triangle>(3.5, 6.8, 4.8, 3.2);
surface.emplace_back<square>(/* whatever */);
surface.render();
}Context
StackExchange Code Review Q#41879, answer score: 4
Revisions (0)
No revisions yet.