2010-02-02 1 views
4

J'essaie d'écrire une application graphique en C++. Il utilise actuellement OGRE pour l'affichage, mais je voudrais qu'il fonctionne avec Irrlicht ou tout autre moteur, même un moteur de rendu personnalisé qui prend en charge mes besoins. C'est une question assez longue, donc j'apprécierais l'aide sur le re-marquage/nettoyage (si nécessaire). Je vais commencer avec un petit arrière-plan.Est-ce que créer une classe de base pour toutes les applications d'un type particulier?

L'application dispose de trois grands Etats:
1. Affichage scène pixellisée
2. Afficher une version tracé de rayons de la même scène
3. Afficher une version hybride de la scène

De toute évidence, je peux diviser mon application en quatre parties principales:
1. Un système de gestion d'état pour basculer entre les modes ci-dessus.
2. Un système d'entrée pouvant recevoir à la fois le clavier et la souris.
3. Le moteur de trame utilisé pour l'affichage.
4. Le système de traçage des rayons. Toute application englobant ce qui précède doit être capable de:
1. Créer une fenêtre.
2. Effectuez toutes les étapes nécessaires pour permettre le rendu dans cette fenêtre.
3. Initialisez le système d'entrée.
4. Initialisez le gestionnaire d'état.
5. Commencer la lecture en boucle (et le rendu!). Je souhaite être en mesure de modifier le moteur de rendu/gestionnaire d'état/système d'entrée/système de suivi des rayons à tout moment, à condition que certaines exigences minimales soient satisfaites. Imho, cela nécessite de séparer l'interface de l'implémentation. Dans cet esprit, j'ai créé les interfaces pour les systèmes ci-dessus. À ce moment-là, j'ai remarqué que l'application avait également une «interface» commune. J'ai donc pensé à l'extraire dans une classe ApplicationBase avec des méthodes virtuelles. Une application spécifique, telle que celle qui utilise OGRE pour la création de fenêtre, le rendu etc. dérivera de cette classe et l'implémentera.

Ma première question est - est-ce une bonne idée de concevoir comme ça?

Voici le code pour la classe de base:

#ifndef APPLICATION_H 
#define APPLICATION_H 
namespace Hybrid 
{ 

    //Forward declarations 
     class StateManager; 
    class InputSystem; 

    //Base Class for all my apps using hybrid rendering. 
    class Application 
    { 
     private: 
      StateManager* state_manager; 
      InputSystem* input_system; 
     public: 
      Application() 
      { 
       try 
       { 
        //Create the state manager 
        initialise_state_manager(); 
        //Create the input system 
        initialise_input_system(); 
       } 
       catch(...) //Change this later 
       { 

        //Throw another exception 
       } 

      } 

      ~Application() 
      {   
       delete state_manager; 
       delete input_system; 
      } 

      //If one of these fails, it throws an 
      //exception. 
      virtual void initialise_state_manager() = 0; 
      virtual void initialise_input_system() = 0; 
      virtual void create_window() = 0; 
      //Other methods. 

    }; 

#endif 

Quand j'utilise OGRE, je compte sur OGRE pour créer la fenêtre. Cela nécessite l'initialisation d'OGRE avant l'appel de la fonction createWindow() dans ma classe dérivée. Bien sûr, tel qu'il est, createWindow va être appelé en premier! Cela me laisse avec les options suivantes:
1. Laissez le constructeur de classe de base vide.
2. Dans l'implémentation de la classe dérivée, effectuez l'initialisation de la partie OGRE de la fonction createWindow.
3. Ajoutez une fonction virtuelle pure initialize render system à ma classe de base. Cela risque de forcer une implémentation fictive dans des classes dérivées qui n'ont aucune utilité pour une telle méthode.

Ma deuxième question est: quelles sont vos recommandations sur le choix d'une de ces stratégies pour initialiser OGRE?

+0

Je ne l'ai pas marqué en langage-agnostique, de peur de recevoir des réponses qui offrent des solutions spécifiques au langage. – batbrat

+1

Quelle est la justification de l'application en tant que classe en premier lieu? – jalf

+0

jalf - C'est une partie de ma question. Si je devais le justifier, je dirais que je peux réutiliser la même séquence d'étapes pour créer et exécuter l'application chaque fois que je change le système d'affichage. Je ne suis pas sûr si je devrais laisser cette partie à la discrétion des utilisateurs (mon) et ne pas la créer du tout. – batbrat

Répondre

3

Vous mélangez deux fonctions non liées dans une classe ici. Premièrement, il sert de raccourci syntaxique pour déclarer et initialiser les membres StateManager et InputSystem. Deuxièmement, il déclare la fonction create_window abstraite.

Si vous pensez qu'il devrait y avoir une interface commune - écrivez une interface (classe abstraite pure).

De plus, écrivez quelque chose comme la classe autonome OgreManager avec les méthodes d'initialisation (en boucle, etc.) et les rappels d'événements. Puisque les applications peuvent créer et initialiser cet objet à tout moment, votre deuxième question est résolue automatiquement.

Votre conception peut enregistrer quelques lignes de code pour la création de nouveaux objets d'application, mais le prix consiste à conserver un objet maître semblable à une soupe avec une ligne d'héritage potentiellement longue.

Utiliser les interfaces et les rappels. P.: pour ne pas mentionner que l'appel de fonctions virtuelles dans le constructeur ne signifie pas ce que vous attendez probablement.

+0

Je pense que l'écriture d'une classe abstraite pure est une meilleure idée que ce que je fais. Créer une classe OgreManager est intéressant. Je pense que ça va résoudre beaucoup de mes problèmes. Merci. +1 – batbrat

2

Oui, c'est un bon design, et c'est celui que j'utilise moi-même.

Pour votre deuxième question, je supprimerais tout élément du constructeur de base qui a la possibilité de ne pas s'appliquer à une classe dérivée. Si OGRE veut créer la fenêtre elle-même, alors vous devez lui permettre de le faire, et je ne pense pas qu'il soit logique d'initialiser OGRE dans createWindow (c'est trompeur).

Vous pouvez ajouter une méthode virtuelle de système de rendu initialize, mais je pense que vous devriez simplement laisser cette tâche au constructeur de la classe dérivée. L'initialisation d'une application est toujours une tâche délicate, et vraiment, vraiment difficile à abstraire. D'après mon expérience, il est préférable de ne faire aucune supposition sur ce que la classe dérivée pourrait vouloir faire, et de le laisser faire le travail lui-même comme il veut. Cela dit, si vous pensez à quelque chose qui s'appliquera absolument à n'importe quelle classe dérivée imaginable, n'hésitez pas à l'ajouter au constructeur de base.

+0

Je suis heureux d'entendre que vous pensez que c'est un bon design. OGRE ne veut pas initialiser la fenêtre elle-même. Je l'ai juste trouvé commode de le faire. Ce fait rend difficile l'ajout du système de rendu initialise à la classe dérivée. Merci pour la réponse :) – batbrat

+0

Je suppose que votre dernier point le couvre. Je pense que je vais aller avec un constructeur de classe de base vide. +1 – batbrat

Questions connexes