tags:

views:

170

answers:

3

How can I implement this fluent interface in C++:

class Base {
public:
  Base& add(int x) {
    return *this;
  }
}

class Derived : public Base {
public:
  Derived& minus(int x) {
    return *this;
  }
}

Derived d;
d.add(1).minus(2).add(3).minus(4);

Current code doesn't work since Base class doesn't know anything about Derived class, etc. I would be very thankful for a hint/suggestion.

+1  A: 

This interface is not possible in C++. You must either make minus() a virtual function within Base or use non-member functions that do some form of type detection.

Don't pull up minus() unless it makes sense in terms of Base.

Noah Roberts
-1 It is hard to say that something is not possible in C++ ;-)
Vicente Botet Escriba
+7  A: 

Make Base class templated. Use the wanted return type of Base the template type, like this:

template <typename T>
class Base {
public:
  T& add(int x) {
    return *static_cast<T *>(this);
  }
}

Then inherit Derived from Base like this:

class Derived : public Base<Derived>

Alternatively (as an answer to Noah's comment), if you don't want to change Base, you could use an intermediate class that performs the casting, like this:

template <typename T>
class Intermediate : public Base {
public:
  T& add(int x) {
    Base::add(x);
    return *static_cast<T *>(this);
  }
}

And let Derived inherit from Intermediate:

class Derived : public Intermediate<Derived>
Patrick
+1. This is also known as the Curiously Recurring Template Pattern: http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
tzaman
Note that any function that operates on base will have to be turned into a template function if you do this.
Noah Roberts
@Noah, I added an alternative where Base does not have to be altered.
Patrick
I'm curious...why `*static_cast<T*>(this)` as opposed to `*reinterpret_cast<T*>(this)`?
Travis Gockel
@Travis because you don't need `reinterpret_cast`. It's way too powerful. `reinterpret_cast` essentially interprets a type as any other type. But in this case the two types are related and they can be casted implicitly. This is what `static_cast` is for: to explicitly ask for an implicit cast. See question #332030.
wilhelmtell
Would you do the same if instead of functions add and minus it was operator += and operator-=?
Vicente Botet Escriba
@Vicente: I know that the solution isn't a perfect one. For every new method on Base you probably need to add the same method to the Intermediate class. Depending on the situation that might be annoying (if Base is often changed), or no problem at all (if Base is never changed), but at least it solves the problem that was asked here.
Patrick
@Patrick +1 I missed that the intermediary class forwards to the base class. BTW shouldn't it be 'return static_cast<T'
Vicente Botet Escriba
+1  A: 

The problem is on your function

  Base& add(int x); 

This is similar to the operator+=(), which must also be overridden to work seamless.

You need to override this function on the derived class.

class Derived : public Base {
public:
  Derived& minus(int x) {
    return *this;
  }
  Derived & add(int x) {
    return  static_cast<Derived &>(this->Base::add(x));
  }
}

in this way d.add(1) will return a reference to d.

Vicente Botet Escriba
and if I have 15 derived classes I have to override add() in every one of them? what if I change Base one day, I have to remember who derives from it?
Vincenzo
You are right, but the compiler will recall it to you. If you can change Base using CRTP as suggested on the accepted answer you avoid it. But this is not always desirable or possible (if you don't owns Base e.g.). Take in account also that now all the functions in Base will be duplicated for each Derived type.
Vicente Botet Escriba