I'm working on a large software, that heavily relies on the call supper antipattern.
Basically, an interface defines an "init()" virtual method that is then overridden in every classes that inherits it. When init() is called on the class, EVERY overloaded init methods are cascaded, from the base class to the top daughter class, and all in between.
But the user HAS to call its direct parent's init() method in its own, which results in code like this:
class myClass : public Base
{
virtual void init()
{
Parent::Init() // often forgotten, or misplaced by the developer
// Do some init stuff
}
}
An alternative to this is usually to use delegates. The Base class has stuff to do in init, that is declared final
in Base, and delegates part of it to an "onInit()" method that inheriting classes should override. But this does not cascade the calls to all parent classes as I'd like it to.
The alternative I've first implemented is a variant of the delegate approach. Both daughter classes and Base implement a onInit() and a init() method. init() calls Parent::init() followed by a call to onInit() on itself, and is auto-generated uing template metaprogramming & macros. and onInit() contains the class-specific code.
# define DELEGATE(T, Parent) \
virtual void init() { Parent::init(); T::onInit(); }
struct Base
{
virtual void init() { onInit(); }
virtual void onInit() {}
};
struct A : public Base
{
DELEGATE(A, Base)
virtual void onInit() { /* MyCustom code for A */ }
}
struct B : public A
{
DELEGATE(B, A)
virtual void onInit() { /* MyCustom code for B */ }
}
This works pretty well.. except that multiple inheritance becomes a mess, and even if handled, diamond inheritance causes issues with duplicated calls.
Which leaves me wondering: I can't be the only person looking for a design pattern solving my issue, and the stackoverflow community must know about it :)
Have you ever encountered a design pattern for this? I'm really looking forward to your ideas!
Aucun commentaire:
Enregistrer un commentaire