I have a composite pattern implementation, used for GUI components:
class CObject {
private:
CObject * m_pParent;
CObjectContainer * m_pChildren;
v
I was thinking about CRTP, but I can not think of a way to keep the dynamic polymorphism along with compile time polymorphism
You can mix them by providing default virtual implementations for certain interfaces using CRTP style base classes.
Thus you have the possibility to aggregate CRTP base implementations (maybe configured with additional 'policy'-template parameters) and still being able to override particular behavior in inherited classes.
Microsoft's ATL library uses this a lot. I also make use of this technique in my STTCL state machine library.
You can add one level of abstraction:
class CObjectBase
{
public:
// Other methods...
virtual CObjectBase* detach() = 0;
virtual CObjectBase* duplicate() const = 0;
};
template <typename Child>
class CObject : public CObjectBase
{
public:
// ...
Child* duplicate() const
{
return new Child(*static_cast<Child*>(this));
}
Child* detach()
{
m_pParent->RemoveChild(this);
m_pParent = nullptr;
return static_cast<Child*>(this); // Cast needed here (inherent to CRTP)
}
std::vector<CObjectBase*> children; // Array possible now
// ...
};
class MyObject : public CObject<MyObject>
{
// ...
};
In natural language: an interface for all objects (CObjectBase
) have a partial implementation for its descendants (CObject<Child>
), which just have to inherit this partial implementation, decreasing the amount of replicated code.
From the snippet alone it is unclear why you need detach()
to return a pointer to a delivered type.
To take advantage of detach()
returning a delivered type, it needs to be called using a reference to the delivered type anyway. Like this:
CSpecificObject* specific_object = new SpecificObject();
// ...
specific_object->detach()->method_declared_in_specific_object();
But this can be replaced with equivalent that works even if detach is void:
specific_object->detach();
specific_object->method_declared_in_specific_object();
If you have a reference to the base type, you can't take advantage of detach()
return type:
CObject* specific_object = new SpecificObject();
//...
// !!! Won't compile:
specific_object->detach()->method_declared_in_specific_object();
For this reason it is unclear what are the advantages of the approach you are trying to implement.
A side not is that the duplicate()
method is smelly. It breaks when delivered class does not overwrite it, but uses the default implementation from the parent class. It can be a sign that something is wrong with the high level design.