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 withs 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 withParams overloaded, some of which don't make sense to include in a GET parameter list.
Thanks in advance!
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;
}
};
Take a look at Curiously recurring template pattern.
If Base is an abstract type (only instantiated in its subclasses) then make it a template taking type name. Your Derive will extend the template - e.g. Derived : public Base<Derived>. If Base is a concrete type - then you will need to introduce a new abstract class that would be a base type for Base and Derived.
This way withFoo can be templated to return real type.
You options are either CRTP (as Mark B illustrated), or using runtime dispatch on the variable name, eg.
Derived d;
d.with("Foo", "foo").with("Bar", "bar").doOutput();
this won't be particularly performant, but it's very flexible, and a good match for protocols which can take arbitrary fields.
Since your types are not polymorphic (no virtual functions) Base has no knoweledge of Derived.
You can reach you objective esentially with static polymorphism:
template<class Derived>
class Base {
protected:
std::string mFoo;
public:
Derived& withFoo(std::string foo) {
mFoo = foo;
return static_cast<Derived&>(*this);
}
};
class Derived : public Base<Derived> {
protected:
......
}
The drawback is that there is anymore a Base class, but as many Base instanciation as are the possible derived, hence you cannot anymore have a Base& or Base* pointing to whatever Derived.
If you need a common-base to collect, you need another CommonBase (not templetized) from which Base can derive from.
Another possibility is making Base (the old one) polimorphic by making withFoo virtual.
At that point, in Derived, you can override withFoo to return the Derived& covariant type:
class Base
{
...
virtual Base& withFoo(...);
...
virtual ~Base() {} //just to make all the hierarchy destructible through base
};
class Derived: public Base
{
...
virtual Derived& withFoo(type arg)
{ return static_cast<Derived&>(Base::withFoo(arg)); }
...
};
This still embrace the classic OOP paradigm, but adds run-time overhead (the vtables) and has the disadvantage it is based on a feature (covariant return type of virtual functions) not all compilers support.
Related
I am attempting to do something like:
class Base {
public:
Base() {
cout << typeid(*this).name() << endl;
}
...
};
class Derived : public Base { ... }
class MoreDerived : public Derived { ... }
Derived d;
MoreDerived m;
Problem is, I always get Base printed to the screen, when I need to see Derived and MoreDerived. Is there a way to get typeid to work this way with derived classes? Or is there another approach besides typeid?
Note: I am adding functionality to an already coded suite, so I don't want to have to add a virtual method to the base class where the derived classes return this value themselves. Also, not worried about runtime overhead, this will be part of a debug compile switch.
In the constructor Base(), the object is still a "Base" instance. It will become a Derived instance after the Base() constructor. Try to do it after the construction and it will work.
See for example :
Avoiding virtual methods in constructor
Never Call Virtual Functions during Construction or Destruction
You can't do that from within a constructor (or destructor) - neither with typeid nor with a virtual method. The reason is while you're in a constructor the vtable pointer is set to the base class being constructed, so the object is of base class and no amount of polymorphism will help at that point.
You have to execute that code after the most derived class has been constructed. One option would be to use a factory function:
template<class T>
T* CreateInstance()
{
T* object = new T();
cout << typeid(*object).name() << endl;
return object;
}
Another option is to provide a virtual toName() function
struct Object{
virtual std::string toName() const = 0;
}
struct Base: Object{
std::string toName()const{ return "Base"; }
}
struct Derived: Base, Object{
std::string toName()const{ return "Derived"; }
This might get tedious since you need to manually create each toName function. But the advantage it gives you is to provide your own custom name.
Suppose I have a base class which cloning of derived classes:
class Base
{
public:
virtual Base * clone()
{
return new Base();
}
// ...
};
I have a set of derived classes which are implemented using a curiously recurring template pattern:
template <class T>
class CRTP : public Base
{
public:
virtual T * clone()
{
return new T();
}
// ...
};
And I attempt to derive from that further like this:
class Derived : public CRTP<Derived>
{
public:
// ...
};
I get compilation errors to the effect of:
error C2555: 'CRTP<T>::clone': overriding virtual function return type differs and is not covariant from 'Base::clone'
I realize this is probably a result of the compiler not fully knowing the inheritance tree for Derived when instantiating CRTP. Furthermore, replacing the return type (T*) with (Base*) also compiles. However, I would like to know if there is a work around which retains the above semantics.
A not-so-pretty workaround.
class Base
{
protected:
virtual Base * clone_p()
{
return new Base();
}
};
template <class T>
class CRTP : public Base
{
protected:
virtual CRTP* clone_p()
{
return new T;
}
public:
T* clone()
{
CRTP* res = clone_p();
return static_cast<T*>(res);
}
};
class Derived : public CRTP<Derived>
{
public:
};
Use dynamic_cast<> instead of static if you feel it's safer.
If you can live with having to use a different syntax for specifying complete types, you might do the following (warning: untested code):
Let's first start with the machinery:
// this gives the complete type which needs to be used to create objects
// and provides the implementation of clone()
template<typename T> class Cloneable:
public T
{
public:
template<typename... U> Cloneable(U&&... u): T(std::forward<U>(u) ...) {}
T* clone() { return new Cloneable(*this); }
private:
// this makes the class complete
// Note: T:: to make it type dependent, so it can be found despite not yet defined
typename T::CloneableBase::CloneableKey unlock() {}
};
// this provides the clone function prototype and also makes sure that only
// Cloneable<T> can be instantiated
class CloneableBase
{
template<typename T> friend class Cloneable;
// this type is only accessible to Clonerable instances
struct CloneableKey {};
// this has to be implemented to complete the class; only Cloneable instances can do that
virtual CloneableKey unlock() = 0;
public:
virtual CloneableBase* clone() = 0;
virtual ~CloneableBase() {}
};
OK, now the actual class hierarchy. That one is pretty standard; no CRTP intermediates or other complications. However no class implements the clone function, but all inherit the declaration (directly or indirectly) from CloneableBase.
// Base inherits clone() from CloneableBase
class Base:
public CloneableBase
{
// ...
};
// Derived can inherit normally from Base, nothing special here
class Derived:
public Base
{
// ...
};
Here's how you then create objects:
// However, to create new instances, we actually need to use Cloneable<Derived>
Cloneable<Derived> someObject;
Derived* ptr = new Cloneable<Derived>(whatever);
// Now we clone the objects
Derived* clone1 = someObject.clone();
Derived* clone2 = ptr->clone();
// we can get rid og the objects the usual way:
delete ptr;
delete clone1;
delete clone2;
Note that a Cloneable<Derived> is-a Derived (it is a subclass), therefore you need to use Cloneable only for construction, and can otherwise pretend to work with Derived objects (well, tyepinfo will also identify it as Cloneable<Derived>).
In the header file .hpp:
class Base{
public:
static /*Some Return Type*/ func(/*Some Datatype*/);
}
class Derived1 public Base{
public:
Derived1();
~Derived1();
}
class Derived1 public Base{
public:
Derived2();
~Derived2();
}
In the cpp file .cpp:
/*Some Return Type*/ Derived1::func(/*Some Datatype*/){
}
/*Some Return Type*/ Derived2::func(/*Some Datatype*/){
}
This obviously fails because there is no way to override a static method in a subclass. But how to obtain the above functionality?
It is mandatory for me to call something like this:
/*Some Return Type*/ result = Derived1::func(/*Some Datatype*/)
/*Some Return Type*/ result = Derived2::func(/*Some Datatype*/)
I know, that abstract method can be defined in the base class like below and then define them in Derived class:
In the header file .hpp:
class Base{
public:
virtual /*Some Return Type*/ func(/*Some Datatype*/) const = 0;
}
But the problem is that virtual methods require object instantiation, which is not I want. I want to call the method without creating an object. If virtual static methods were allowed, they would have served the purpose.
The only alternative that I can think of is to declare the function func() in all the Derived classes in the header file and remove it from the Base class. Is there any alternative method to do it? So that the declaration is only once in the Base class and all the Derived classes only have to define them, not redeclare?
Calling a virtual function without an object is a contrasense,
since the resolution depends on the type of the object.
are cases where you might need to call the same function
dependant on the type of an object, or specifying the class
explicitly, without an object. This is easily handled by using
two functions, one static, and one virtual. (Typically, the
virtual one will just forward to the static.)
EDIT:
A simple example (from actual code):
#define DECLARE_CLASS_NAME(className) \
static char className() { return STRINGIZE(className); } \
virtual char* getClassName() { return className(); }
class Base
{
public:
DECLARE_CLASS_NAME(Base);
// ...
};
class Derived : public Base
{
public:
DECLARE_CLASS_NAME(Derived);
// ...
};
and so on, in all of the derived classes. This was used to
obtain the type names for serialization, for example:
std::string typeName = pObj->getClassName();
and also as a primitive RTTI (this was about 20 years ago):
if ( pObj->getClassName() == Derived::className() ) ...
(We had established the rule that the only way you could obtain
the name of a class was by using one of these functions. That
effectively internalized the names of the classes, and allowed
simple pointer comparisons to work. On the systems we were
working on then, this was important.)
You can do that a bit hacky =)
//header file
template<class T>
struct base_t
{
static void do_smth();
};
struct derived1_t : base_t<derived1_t>
{
};
struct derived2_t : base_t<derived2_t>
{
};
//cpp file
void base_t<derived1_t>::do_smth() // `note base_t<derived1_t>::` instead of `derived1_t::`
{
std::cout << "aaa" << std::endl;
}
PS: very strange that you do not want to declare this function in derived classes, because when you use virtual functions you should declare them in derived class
One possibility is to only define them in the derived classes:
struct Base
{
// nothing
};
struct Derived1 : public Base
{
static void func() { /*...*/ }
};
struct Derived2 : public Base
{
static void func() { /*...*/ }
};
This allows you to call:
Derived1::foo();
Derived2::foo();
Calling it for the base type and expecting the compiler to figure out which subtype you mean cannot work:
// How will the compiler know to choose
// between Derived1:: func or Derived2:: func ?
Base::func();
You might want to look at CRTP or type-traits for alternative approaches.
Say you have a base class Dep for a tree of classes. There is a virtual method Dep* Dep::create() that I want to be implemented by every single leaf class. Is there any way to enforce this?
Note: The problem here is that there could be intermediate classes (say class B : public A : public Dep) implementing this method (A::create) by accident or because they think they are leaf classes, but are in fact subclassed themselves.
The question ends here.
Context
If you are curious why I need this; I have a class Master which has Dep objects of unknown concrete type. If Master is duplicated, I need to come up with a matching clone of the Dep instance. Next best thing to do is the virtual constructor idiom, which introduces precisely this problem.
Additionally, I cannot even catch this (other then by crashing horribly), because for obscure reasons, people that have more to say than me, have outlawed dynamic_cast in this project (perhaps this is a good decision; But anyways a completely different discussion).
C++ provides no way to keep a class from inheriting from your class, and there is no way to make a particular class in the inheritance hierarchy implement a method. The only rule is that somewhere in the inheritance hierarchy above a particular class (not necessarily in the leaf) all virtual functions must have an implementation for that class to be instantiatable.
For instance, A could inherit from Def and implement all it's [pure] virtual methods. Then if B inherits from A, it doesn't have to implement anything. There's no way to keep that from happening.
So the answer is no, there is no way to enforce this.
Using curiously recurring template fun, you can achieve something quite similar:
template<typename T>
class Cloneable : public T, public Dep
{
private:
Cloneable<T>() : T() { }
public:
static Cloneable<T>* Create() { return new Cloneable<T>(); }
Cloneable<T>* clone() { return new Cloneable<T>(*this); }
};
Instead of deriving from Dep and instantiating via new MyType, use Cloneable<MyType>::Create. Since Cloneable<MyType> is derived from MyType, you can use the instance the same way you would use any MyType, except that it is now guaranteed to have Dep::clone.
Additionally your Master should not accept an instance of type Dep, but enforce that it is a Cloneable<T>. (Replace your orignial function by a simple function template that enforces this.) This guarantees that any Dep inside the master has a correctly implemented clone function.
Since Cloneable<MyType> has no public constructor, it cannot be inherited, however your actual MyType can be further inherited and used just as before.
Did TPTB outlaw all RTTI, or only dynamic_cast<>()? If you can use RTTI, then you can enforce the existence of the method as a postcondition of calling it:
#include <typeinfo>
#include <cassert>
#include <iostream>
#include <stdexcept>
class Base {
protected:
virtual Base* do_create() = 0;
virtual ~Base() {}
public:
Base* create() {
Base *that = this->do_create();
if( typeid(*this) != typeid(*that) ) {
throw(std::logic_error(std::string() +
"Type: " +
typeid(*this).name() +
" != " +
typeid(*that).name()));
}
return that;
}
};
class Derive1 : public Base {
protected:
Base* do_create() { return new Derive1(*this); }
};
class Derive2 : public Derive1 {};
void f(Base*p) { std::cout << typeid(*p).name() << "\n"; }
int main() {
Derive1 d1;
Base *pD1 = d1.create(); // will succeed with correct semantics
Derive2 d2;
Base *pD2 = d2.create(); // will throw exception due to missing Derive2::do_create()
}
If you control the base class AbstractDep then you can enforce that concrete leaf classes must be created by using a class template WithCloning. This leaf can then be sealed so that it cannot be inherited. Or more precisely, instances cannot be created of a derived class.
class AbstractDep
{
template< class Type > friend class WithCloning;
private:
enum FooFoo {};
virtual FooFoo toBeImplementedByLeafClass() = 0;
public:
virtual AbstractDep* clone() const = 0;
};
template< class Type > class WithCloning;
class Sealed
{
template< class Type > friend class WithCloning;
private:
Sealed() {}
};
template< class Type >
class WithCloning
: public Type
, public virtual Sealed
{
private:
AbstractDep::FooFoo toBeImplementedByLeafClass()
{
return AbstractDep::FooFoo();
}
public:
virtual WithCloning* clone() const
{
return new WithCloning( *this );
}
};
typedef WithCloning<AbstractDep> Dep;
class AbstractDerivedDep
: public AbstractDep
{
// AbstractDep::FooFoo toBeImplementedByLeafClass(); // !Not compile.
public:
};
typedef WithCloning<AbstractDerivedDep> DDep;
struct Foo: Dep {}; // !Does not compile if instantiated.
int main()
{
Dep d;
//Foo f;
}
If the classes require more than default construction then that most be solved additionally.
One solution is then to forward an argument pack from the WithCloning constructor (there is an example C++98 implementation on my blog, and C++0x supports that directly).
Summing up, to be instantiable the class must be WithCloning.
Cheers & hth.,
when you say that they are unknown, i presume they still inherit from a common base class /interface right?
only thing i can think of you can use to force is on the virtual base class add
virtual Base* clone() {
assert( 1==0 ); //needs to be overriden
}
so you are forced to override, but this is only detected at run-time when trying to call clone on a instance of a class that is missing the override
even if you are not allowed to use dynamic_cast or RTTI, you can still enable it for debug purposes locally on your build, if that will help you find the typeid of offending classes
it sounds like you are familiar with the clone pattern, but i'll post it quietly in here, and we can forget about it:
http://www.cplusplus.com/forum/articles/18757/
I am attempting to do something like:
class Base {
public:
Base() {
cout << typeid(*this).name() << endl;
}
...
};
class Derived : public Base { ... }
class MoreDerived : public Derived { ... }
Derived d;
MoreDerived m;
Problem is, I always get Base printed to the screen, when I need to see Derived and MoreDerived. Is there a way to get typeid to work this way with derived classes? Or is there another approach besides typeid?
Note: I am adding functionality to an already coded suite, so I don't want to have to add a virtual method to the base class where the derived classes return this value themselves. Also, not worried about runtime overhead, this will be part of a debug compile switch.
In the constructor Base(), the object is still a "Base" instance. It will become a Derived instance after the Base() constructor. Try to do it after the construction and it will work.
See for example :
Avoiding virtual methods in constructor
Never Call Virtual Functions during Construction or Destruction
You can't do that from within a constructor (or destructor) - neither with typeid nor with a virtual method. The reason is while you're in a constructor the vtable pointer is set to the base class being constructed, so the object is of base class and no amount of polymorphism will help at that point.
You have to execute that code after the most derived class has been constructed. One option would be to use a factory function:
template<class T>
T* CreateInstance()
{
T* object = new T();
cout << typeid(*object).name() << endl;
return object;
}
Another option is to provide a virtual toName() function
struct Object{
virtual std::string toName() const = 0;
}
struct Base: Object{
std::string toName()const{ return "Base"; }
}
struct Derived: Base, Object{
std::string toName()const{ return "Derived"; }
This might get tedious since you need to manually create each toName function. But the advantage it gives you is to provide your own custom name.