method chaining with polymorphism c++
c++, fluent, polymorphism
Solution
I think you could utilize CRTP here, something like the following, where the derived class tells the base what type it is:
class Base
{
// Abstract/virtual interface here.
};
template <class Derived>
class Base_T : public Base
{
private:
std::string mFoo;
public:
Derived& withFoo(std::string foo) {
mFoo = foo;
return *static_cast<Derived*>(this);
}
};
class Derived : public Base_T<Derived> {
private:
std::string mBar;
public:
Derived& withBar(std::string bar) {
mBar = bar;
return *this;
}
void doOutput() {
std::cout << "Foo is " <<
mFoo << ". Bar is " <<
mBar << "." << std::endl;
}
};
Problem
Is it possible to write fluent chanining methods that return a derived type? Consider the following two classes: ``` class Base { protected: std::string mFoo; public: Base& withFoo(std::string foo) { mFoo = foo; return *this; } }; class Derived : public Base { protected: std::string mBar; public: Derived& withBar(std::string bar) { mBar = bar; return *this; } void doOutput() { std::cout << "Foo is " << mFoo << ". Bar is " << mBar << "." << std::endl; } }; ``` I would then like to build my object and use it like this: ``` Derived d; d.withFoo("foo").withBar("bar").doOutput(); ``` This of course fails since `withFoo` returns a `Base`. Since all my `with` methods simply set member variables, I can specify the derived `with`s first. The problem is my builder method (`doOutput` in the example above) would then need to be a separate statement. ``` Derived d; d.withBar("this is a bar") .withFoo("this is my foo"); d.doOutput(); ``` My question is whether there is some way for `withFoo` to return an unknown derived type so that `Base` may be used seamlessly with multiple derived classes (after all, `*this` is a `Derived`, although `Base` (correctly) is unaware of the fact). For a more concrete example, I'm writing a few classes to access a REST server. I have a `RestConnection` class with method `withUrl`, a `PostableRest` class with methods `withParam` and `doPost`, and a `GettableRest` class with `doGet`. I suspect this is not possible and will probably try cramming a bunch of virtual methods into `RestConnection` but I hate to do that when there are multiple `withParam`s overloaded, some of which don't make sense to include in a GET parameter list. Thanks in advance!