Ne craignez pas...
Je suppose que ton problème est lié à la familiarité, pas la technologie. Familiarisez-vous avec le C++ programmation orientée objet.
C++ est un langage de programmation orientée objet
Parmi ses multiples paradigmes, il a de la POO fonctionnalités et est plus que capable de soutenir la comparaison avec la plupart pur langage OO.
Ne laissez pas le "C partie à l'intérieur de C++" vous faire croire que C++ ne peut pas traiter avec d'autres paradigmes. C++ peut gérer beaucoup de paradigmes de programmation tout à fait gracieusement. Et parmi eux, la programmation orientée objet C++ est le plus mature de C++ paradigmes après la procédure de paradigme (c'est à dire le fameux "C").
Le polymorphisme est Ok pour la production
Il n'y a pas de "bogues" ou "ne convient pas pour la production de code" de la chose. Il y a des développeurs qui restent ancrés dans leurs habitudes, et les développeurs qui allez apprendre à utiliser les outils et l'utilisation des meilleurs outils pour chaque tâche.
l'interrupteur et le polymorphisme sont presque similaire...
... Mais polymorphisme supprimé la plupart des erreurs.
La différence est que vous devez gérer les commutateurs manuellement, alors que le polymorphisme est plus naturel, une fois que vous avez utilisé avec de l'héritage de la redéfinition de méthode.
Avec les commutateurs, vous aurez pour comparer une variable de type avec différents types, et de gérer les différences. Avec le polymorphisme, la variable elle-même ne sait comment se comporter. Vous n'avez qu'à organiser les variables dans la logique des moyens, et de remplacer les bonnes méthodes.
Mais en fin de compte, si vous oubliez de s'occuper d'une affaire en switch, le compilateur ne vous dis pas, alors que l'on vous dira si vous dériver d'une classe sans écraser ses méthodes virtuelles pures. Ainsi, la plupart des switch-les erreurs sont évitées.
Dans l'ensemble, les deux caractéristiques sont sur les choix à faire. Mais Polymorphisme de vous permettre de faire plus complexe et, dans le même temps, de plus naturel et donc plus de choix.
Évitez d'utiliser des RTTI à trouver un type d'objet
RTTI est un concept intéressant, et peut être utile. Mais la plupart du temps (c'est à dire 95% du temps), la redéfinition de méthode et l'héritage sera plus que suffisant, et la plupart de votre code doit même pas connaître le type exact de l'objet manipulé, mais la confiance, à faire la bonne chose.
Si vous utilisez RTTI comme une simple interrupteur, vous êtes à côté de la question.
(Disclaimer: je suis un grand fan de la RTTI concept et de dynamic_casts. Mais on doit utiliser le bon outil pour la tâche à accomplir, et la plupart du temps de RTTI est utilisé comme une simple interrupteur, ce qui est faux)
Comparer dynamique vs statique polymorphisme
Si votre code ne connais pas le type exact d'un objet au moment de la compilation, puis utilisez polymorphisme dynamique (c'est à dire classique héritage, méthodes virtuelles primordial, etc.)
Si votre code ne connaît la nature au moment de la compilation, alors peut-être que vous pourriez utiliser polymorphisme statique, c'est à dire le modèle PFI http://en.wikipedia.org/wiki/Curiously_Recurring_Template_Pattern
Le PROGRAMME vous permettra d'avoir un code qui sent le polymorphisme dynamique, mais dont chaque appel de méthode sera résolu statiquement, ce qui est idéal pour certains très critique de code.
La Production de code exemple
Un code similaire à celui-ci (de mémoire) est utilisé sur la production.
La plus simple solution de révolution autour de la procédure appelée par la boucle de message (un WinProc dans Win32, mais j'ai écrit une version plus simple, pour des raisons de simplicité). Afin de résumer, c'était quelque chose comme:
void MyProcedure(int p_iCommand, void *p_vParam)
{
// A LOT OF CODE ???
// each case has a lot of code, with both similarities
// and differences, and of course, casting p_vParam
// into something, depending on hoping no one
// did a mistake, associating the wrong command with
// the wrong data type in p_vParam
switch(p_iCommand)
{
case COMMAND_AAA: { /* A LOT OF CODE (see above) */ } break ;
case COMMAND_BBB: { /* A LOT OF CODE (see above) */ } break ;
// etc.
case COMMAND_XXX: { /* A LOT OF CODE (see above) */ } break ;
case COMMAND_ZZZ: { /* A LOT OF CODE (see above) */ } break ;
default: { /* call default procedure */} break ;
}
}
Chaque ajout de la commande ajout d'un cas.
Le problème est que certaines commandes similaires, et partagé en partie, par leur mise en œuvre.
Donc, en mélangeant le cas d'un risque pour l'évolution.
J'ai résolu le problème en utilisant le modèle de Commande, qui est, la création d'une base de l'objet de Commande, avec une méthode process ().
J'ai donc ré-écrit le message de la procédure, en minimisant le code dangereux (c'est à dire jouer avec void *, etc.) à un minimum, et il a écrit pour être sûr que je n'aurais jamais besoin de le toucher à nouveau:
void MyProcedure(int p_iCommand, void *p_vParam)
{
switch(p_iCommand)
{
// Only one case. Isn't it cool?
case COMMAND:
{
Command * c = static_cast<Command *>(p_vParam) ;
c->process() ;
}
break ;
default: { /* call default procedure */} break ;
}
}
Puis, pour chaque commande, au lieu d'ajouter du code dans la procédure, et le mélange (ou pire, de le copier/coller) le code à partir des commandes similaires, j'ai créé une nouvelle commande, et la dérivée à partir de l'objet de Commande, ou l'un de ses objets dérivés:
Cela a conduit à la hiérarchie (représentés par un arbre):
[+] Command
|
+--[+] CommandServer
| |
| +--[+] CommandServerInitialize
| |
| +--[+] CommandServerInsert
| |
| +--[+] CommandServerUpdate
| |
| +--[+] CommandServerDelete
|
+--[+] CommandAction
| |
| +--[+] CommandActionStart
| |
| +--[+] CommandActionPause
| |
| +--[+] CommandActionEnd
|
+--[+] CommandMessage
Maintenant, tout ce que j'avais à faire était de remplacer les processus pour chaque objet.
Simple et facile à étendre.
Par exemple, dire que le CommandAction était censé faire son processus en trois phases: "avant", "pendant" et "après". Son code serait quelque chose comme:
class CommandAction : public Command
{
// etc.
virtual void process() // overriding Command::process pure virtual method
{
this->processBefore() ;
this->processWhile() ;
this->processAfter() ;
}
virtual void processBefore() = 0 ; // To be overriden
virtual void processWhile()
{
// Do something common for all CommandAction objects
}
virtual void processAfter() = 0 ; // To be overriden
} ;
Et, par exemple, CommandActionStart pourrait être codé sous la forme:
class CommandActionStart : public CommandAction
{
// etc.
virtual void processBefore()
{
// Do something common for all CommandActionStart objects
}
virtual void processAfter()
{
// Do something common for all CommandActionStart objects
}
} ;
Comme je l'ai dit: Facile à comprendre (si un commentaire est correctement), et très facile à étendre.
Le commutateur est réduite à son strict minimum (c'est à dire si-comme, parce que nous avons encore besoin de déléguer des commandes de Windows à Windows par défaut de la procédure), et pas besoin de RTTI (ou pire, dans la maison de RTTI).
Le même code à l'intérieur d'un switch serait assez amusant, je suppose (si ce n'est à en juger par la quantité de "historiques" du code, j'ai vu dans notre application au travail).