En suivant une règle simple pour dériver à travers une classe modèle, c'est possible.
#include <iostream>
struct TEvent
{
};
struct Base {
virtual void CallOnEvent(TEvent * e)
{
OnEvent(e);
}
virtual void OnEvent(TEvent * e)
{
std::cout << "Base::Event" << std::endl;
}
void CallUp(TEvent * e)
{
}
};
template <typename B>
struct TDerived : public B
{
void CallUp( TEvent * e )
{
B::CallUp(e);
B::OnEvent(e);
}
virtual void CallOnEvent( TEvent * e )
{
CallUp(e);
this->OnEvent(e);
}
};
struct Derived01 : public TDerived< Base >
{
void OnEvent(TEvent * e)
{
std::cout << "Derived01::Event" << std::endl;
}
};
struct Derived02 : public TDerived< Derived01 >
{
void OnEvent(TEvent * e)
{
std::cout << "Derived02::Event" << std::endl;
}
};
struct Derived03 : public TDerived< Derived02 >
{
void OnEvent(TEvent * e)
{
std::cout << "Derived03::Event" << std::endl;
}
};
struct Derived04 : public TDerived< Derived03 >
{
void OnEvent(TEvent * e)
{
std::cout << "Derived04::Event" << std::endl;
}
};
int main( void )
{
Derived04 lD4;
lD4.CallOnEvent(0);
return 0;
}
Ce code donne ( codepad ):
Base::Event
Derived01::Event
Derived02::Event
Derived03::Event
Derived04::Event
Concernant certaines réponses utilisant typeid
. Je n'envisagerais jamais d'utiliser typeid
pour autre chose que le débogage. Cela est dû à deux choses :
- la vérification dynamique des types peut être effectuée d'une manière beaucoup plus efficace (sans créer d'erreur de type).
type_info
c'est-à-dire en utilisant dynamic_cast
certaines méthodes
- La norme C++ ne garantit que l'existence du typeid, mais pas vraiment la façon dont il fonctionne (la plupart des choses sont spécifiques au compilateur).
editar:
Un exemple légèrement plus complexe avec un héritage multiple. Celui-ci n'est malheureusement pas soluble sans appels explicites dans les classes qui héritent de bases multiples (principalement parce que ce qui doit se passer dans de tels cas n'est pas clair, nous devons donc définir explicitement le comportement).
#include <iostream>
struct TEvent
{
};
struct Base {
virtual void CallOnEvent(TEvent * e)
{
OnEvent(e);
}
virtual void OnEvent(TEvent * e)
{
std::cout << "Base::Event" << std::endl;
}
void CallUp(TEvent * e)
{
}
};
template <typename B >
struct TDerived : public B
{
void CallUp( TEvent * e )
{
B::CallUp(e);
B::OnEvent(e);
}
virtual void CallOnEvent( TEvent * e )
{
CallUp(e);
this->OnEvent(e);
}
};
struct Derived01 : virtual public TDerived< Base >
{
void OnEvent(TEvent * e)
{
std::cout << "Derived01::Event" << std::endl;
}
};
struct Derived02 : virtual public TDerived< Derived01 >
{
void OnEvent(TEvent * e)
{
std::cout << "Derived02::Event" << std::endl;
}
};
typedef TDerived< Derived02 > TDerived02;
typedef TDerived< Derived01 > TDerived01;
struct Derived03 : virtual public TDerived02, virtual public TDerived01
{
void OnEvent(TEvent * e)
{
std::cout << "Derived03::Event" << std::endl;
}
virtual void CallOnEvent( TEvent * e )
{
CallUp(e);
Derived03::OnEvent(e);
}
void CallUp( TEvent * e )
{
TDerived02::CallUp(e);
TDerived01::CallUp(e);
}
};
struct Derived04 : public TDerived< Derived03 >
{
void OnEvent(TEvent * e)
{
std::cout << "Derived04::Event" << std::endl;
}
};
int main( void )
{
Derived04 lD4;
Derived03 lD3;
lD3.CallOnEvent( 0 );
std::cout << std::endl;
lD4.CallOnEvent( 0 );
return ( 0 );
}
Le résultat est ( idéone ):
Base::Event \ \
Derived01::Event | - from Derived02 |
Derived02::Event / |-- from Derived03
Base::Event \__ from Derived01 |
Derived01::Event / |
Derived03::Event /
Base::Event \ \ \
Derived01::Event | - from Derived02 | |
Derived02::Event / |-- from Derived03 |-- from Derived04
Base::Event \__ from Derived01 | |
Derived01::Event / | |
Derived03::Event / |
Derived04::Event /