HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Fluent interface and polymorphism for building a scene with shapes

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
withpolymorphismbuildinginterfaceshapesforandfluentscene

Problem

I would like to improve the interfaces of some polymorphic classes going from positional to named parameters and I came up with the fluent interface.

The following is the most clean, compact and compilable (-std=c++11 required) example that I have been able to come up with:

#include 
#include 
#include 
#include 

using namespace std;

struct Figure {
  string _name;
  Figure * name(const string & str) { _name=str; return this; }
  virtual double area() const=0;
};

struct Circle: Figure {
  double _radius;
  Circle * radius(double r) { _radius=r; return this;}
  double area() const override {return M_PI*_radius*_radius;}
};

struct Square: Figure {
  double _side;
  Square * side(double s) { _side=s; return this;}
  double area() const override {return _side*_side;}
};

struct Scene {
  vector v;
  ~Scene() { for (auto & f : v) delete f; }
  Scene & add(Figure * f) {v.push_back(f); return *this;}
  double total_area() const {
    double total=0;
    for (auto f : v) total += f->area();
    return total;
  }
};

int main() {
  Scene scene;
  scene.add((new Circle)->radius(1.)->name("c1"))
       .add((new Square)->  side(1.)->name("s1"));
  cout << "Total area: " << scene.total_area() << endl;
  return 0;
}


I have a couple of issues with this:

  • That is an ugly place to have a new operator, could it be avoided somehow?



  • After having called the method name("name") the type is lost so there is still an ordering to respect: add((new Square)->name("s1")->side(1.)) will not compile. You should imagine to have many levels of inheritance and lots of parameters to be setted!



How would you address these issues and improve the code? C++1y is allowed and preferred to Boost?

For further improvements see the related question: Variadic templates and pointers to member functions to achieve a named-parameters interface in C++

Solution

Another thing to consider in your current design:

~Scene() { for (auto & f : v) delete f; }


You are calling the destructor of the base here, not the derived classes' destructors. Remember to make a virtual destructor in your class to solve this problem.

Code Snippets

~Scene() { for (auto & f : v) delete f; }

Context

StackExchange Code Review Q#42647, answer score: 9

Revisions (0)

No revisions yet.