IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Problème de cast ou de design


Sujet :

C++

  1. #21
    Membre éclairé Avatar de LinuxUser
    Inscrit en
    Avril 2007
    Messages
    857
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 857
    Par défaut
    Je vais essayer d'être clair.
    J'ai créé un exemple bidon pour reproduire mon problème, avec une classe mère "Methode", deux filles "Simple" et "Complexe", une classe "MethodeUser" qui utilise les méthodes et une classe "User".
    Je répète que les fonctions et calculs n'ont pas de sens, et servent juste pour illustrer.

    Classe Methode:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    #ifndef METHODE_H_
    #define METHODE_H_
     
    #include <vector>
     
    class Methode
    {
    public:
    /******************************** CONSTRUCTOR *********************************/
    	/**
             * @brief Default constructor.
             */
    	Methode();
    /********************************* DESTRUCTOR *********************************/
    	/**
             * @brief Default destructor.
             */
    	virtual ~Methode();
    /*********************************** METHODS **********************************/
    	virtual double calculation(double& a, double& b) const=0;
    	virtual function1(double& a) = 0;
    	void printInputsValues() const;
    	void printSolutionValue() const;
     
    protected:
    	double m_solution;
    	std::vector<double> m_inputs;
     
    };
     
    #endif /* METHODE_H_ */
    Classe Simple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    #ifndef SIMPLE_H_
    #define SIMPLE_H_
     
    #include "Methode.h"
     
    class Simple: public Methode
    {
    public:
    /******************************** CONSTRUCTOR *********************************/
    	/**
             * @brief Default constructor.
             */
    	Simple();
    /********************************* DESTRUCTOR *********************************/
    	/**
             * @brief Default destructor.
             */
    	virtual ~Simple();
    /*********************************** METHODS **********************************/
    	virtual double calculation(double& a, double& b);
    	virtual void function1(double& a);
    /*********************************** GETTERS **********************************/
    private:
    	double m_coeff;
     
    };
     
    #endif /* SIMPLE_H_ */
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    #include "Simple.h"
     
    double Simple::calculation(double a, double b)
    {
      double res = 0.0;
     
      function1(a);
     
      res = a + m_inputs[b];
     
      return (res);
    }
     
    void Simple::function1(double& a)
    {
      int i=0;
      for(i=0;i<m_inputs.size();++i)
      {
        m_inputs[i] = m_coeff*a;
      }
    }
    Classe Complexe
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    #ifndef COMPLEXE_H_
    #define COMPLEXE_H_
     
    #include "Methode.h"
     
    class Complexe: public Methode
    {
    public:
    /******************************** CONSTRUCTOR *********************************/
    	/**
             * @brief Default constructor.
             */
    	Complexe();
    /********************************* DESTRUCTOR *********************************/
    	/**
             * @brief Default destructor.
             */
    	virtual ~Complexe();
    /*********************************** METHODS **********************************/
    	virtual double calculation(double& a, double& b);
    	virtual void function1(double& a);
    	void function2(double& a);
    /*********************************** GETTERS **********************************/
    private:
    	double m_alpha;
    	double m_epsilon;
    	double m_sigma;
    	std::vector<double> m_angle;
     
    };
     
    #endif /* COMPLEXE_H_ */
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    #include "Comlexe.h"
     
    double Comlexe::calculation(double a, double b)
    {
      double res = 0.0;
     
      function1(a);
      function2(a);
     
      res = a + m_inputs[b];
     
      return (res);
    }
     
    void Comlexe::function1(double& a)
    {
      int i=0;
      for(i=0;i<m_inputs.size();++i)
      {
        m_inputs[i] = m_sigma*a + m_epsilon;
      }
    }
     
    void Comlexe::function2(double& a)
    {
      int i = 0;
      for(i=0;i<m_inputs.size();++i)
      {
        a += m_alpha[i] + m_inputs[i];
      }
    }
    Classe MethodeUser
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    #ifndef METHODEUSER_H_
    #define METHODEUSER_H_
     
    #include "Methode.h"
     
    class MethodeUser
    {
    public:
    /******************************** CONSTRUCTOR *********************************/
    	/**
             * @brief Default constructor.
             */
    	MethodeUser();
    /********************************* DESTRUCTOR *********************************/
    	/**
             * @brief Default destructor.
             */
    	virtual ~MethodeUser();
    /*********************************** METHODS **********************************/
    	double useMethode(Methode& m, double& a, double& b);
    /*********************************** GETTERS **********************************/
    private:
     
    };
     
    #endif /* METHODEUSER_H_ */
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    #include "MethodeUser.h"
     
     
    double MethodeUser::useMethode(Methode& m, double& a, double& b)
    {
      return m.calculation(double a, double b);
    }
    Classe User
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    #ifndef USER_H_
    #define USER_H_
     
    #include "Simple.h"
    #include "Complexe.h"
     
    #include "MethodeUser.h"
     
    class User
    {
    public:
    /******************************** CONSTRUCTOR *********************************/
    	/**
             * @brief Default constructor.
             */
    	User();
    	User(MethodeMode mode);
    /********************************* DESTRUCTOR *********************************/
    	/**
             * @brief Default destructor.
             */
    	virtual ~User();
    /*********************************** METHODS **********************************/
    	void solve();
    /*********************************** GETTERS **********************************/
    private:
    	ModelUser m_modelUser;
    	Simple m_methodeSimple;
    	Complexe m_methodeComplexe;
    	MethodeMode m_mode;
    };
     
    #endif /* USER_H_ */
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    #include "User.h"
     
    void User::solve()
    {
      double a = 3.14;
      double b = 1.51;
     
      if(m_mode==SIMPLE)
      {
        m_modelUser.useMethode(m_methodeSimple, a, b);
      }
      else if(m_mode==COMPLEXE)
      {
        m_modelUser.useMethode(m_methodeComplexe, a, b);
      }
      else
      {// errror: unknown mode
      }
    }
    Voilà le décor est posé.

    Je voudrais pouvoir faire :

    1. dans User.h, remplacer les attributs de méthodes par un seul attribut générique
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    private:
    	//Simple m_methodeSimple;
    	//Complexe m_methodeComplexe;
            Methode methode;
    Je pourrais le faire dans ce petit exemple, mais je pourrai plus appeler de méthodes propres aux classe filles.


    2. pouvoir appler des méthodes propres aux classe filles dans MethodeUser:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    double MethodeUser::useMethode(Methode& m, double& a, double& b)
    {
        // par exemple initialiser m_angle qui appartient à Complexe
        std::vector<double> angle = std::vector<double>(SIZE, 13);
        m.initializeAngle(angle);
     
        return m.calculation(double a, double b);
    }
    pour eviter d'avoir deux fonctions qui font presque la même chose:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    double MethodeUser::useMethode(Simple& m, double& a, double& b);
    double MethodeUser::useMethode(Complexe& m, double& a, double& b);
    Même je n'ai aucunes excues, je précise qu'à ma décharge, on m'avait dis que les (vraies) classes "Simple" et "Complexe" auraient exactement les mêmes caractéristiques, donc quand j'ai fais le design j'ai naturellement pensé à l'héritage.
    C'est par la suite que j'ai commencé à "bricoler" pour que tout ce tienne.

  2. #22
    Membre Expert
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Par défaut
    Tu veux faire des choses contradictoires :
    - ne pas conserver l’information de type réel de Methode en le considérant par sa classe mère
    - conserver l’information de type réel de Methode en appelant des méthodes spécifiques.

    Fatalement, ça ne marche pas.

    Plusieurs possibilités pour y remédier :
    - conserver l’information du type réel --> ça va t’amener à utiliser un variant (je préfère largement çà à du downcasting, qui marche aussi)
    - modifier l’interface de la classe mère pour que les traitements soient appelés indifféremment du type réel, quitte à ce qu’ils ne fassent rien (pas terrible)
    - utiliser un pattern visiteur

  3. #23
    Membre éclairé Avatar de LinuxUser
    Inscrit en
    Avril 2007
    Messages
    857
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 857
    Par défaut
    Citation Envoyé par white_tentacle Voir le message
    Tu veux faire des choses contradictoires :
    - ne pas conserver l’information de type réel de Methode en le considérant par sa classe mère
    - conserver l’information de type réel de Methode en appelant des méthodes spécifiques.
    C'est exactement ce que je cherche à faire (malheureusement).

    Citation Envoyé par white_tentacle Voir le message
    - conserver l’information du type réel --> ça va t’amener à utiliser un variant (je préfère largement çà à du downcasting, qui marche aussi)
    Ca impliquerait une duplication du code en doublant plusieurs fonctions (une pour chaque type réel).
    Je vois pas en quoi le downcasting(qui m'interesse pas non plus) est pire, j'aurais pensé qu'il vaille mieux caster que créer des doublons.
    Citation Envoyé par white_tentacle Voir le message
    - modifier l’interface de la classe mère pour que les traitements soient appelés indifféremment du type réel, quitte à ce qu’ils ne fassent rien (pas terrible)
    En effet, pas terrible du tout, je passe mon chemin.

    Citation Envoyé par white_tentacle Voir le message
    - utiliser un pattern visiteur
    La solution là voilà donc, je vais devoir m'y mettre à présent.

    Merci beaucoup en tout cas de votre aide.

  4. #24
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 407
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 407
    Par défaut
    Mais le pattern visiteur implique de surcharger selon les types réels, au moins à un point.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  5. #25
    Membre Expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Par défaut
    J'ai du mal à saisir le code. Il n'y aurait pas un ModelUser qui se serait transformé en MethodUser (ou l'inverse) ?

    Ceci dit, ce que tu brises, ce n'est pas tant le LSP qu'un "principe" beaucoup plus fondamental : l'encapsulation. Pourquoi est-ce que ça serait à MethodeUser de savoir comment doivent se comporter les classes filles de Methode ? Si tu mets toutes les fonctions (exceptées calculation) privées, tu peux écrire le code que tu souhaites - en poussant la difficulté dans les classes filles, et non pas dans l'appelant.

    Ou y-a-t-il quelque chose que tu ne nous a pas dit ?
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  6. #26
    Membre Expert
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Par défaut
    Citation Envoyé par LinuxUser Voir le message
    Je vois pas en quoi le downcasting(qui m'interesse pas non plus) est pire, j'aurais pensé qu'il vaille mieux caster que créer des doublons.
    Je réponds juste à ce point, mais la différence fondamentale, c’est que :
    - le nombre de classes pouvant dériver d’une mère est infini et inconnu à la compilation (du moins en c++)
    - le nombre de types contenus dans un variant est fini et connu à la compilation

    Dans le premier cas (downcast), tu as la certitude que tu vas un jour « oublier » de gérér un type que tu rajoutes à un endroit dans ton code.

    Dans le deuxième cas, ton compilateur (avec les bonnes options évidemment, mais tu fais les choses bien ) va te péter des avertissements et te prémunir d’erreurs.

Discussions similaires

  1. [CASTS]problème de cast de Time
    Par DeVoN dans le forum Langage
    Réponses: 7
    Dernier message: 22/02/2006, 17h24
  2. [JDBC Driver][JSTL] Problème de cast de données
    Par GyLes dans le forum PostgreSQL
    Réponses: 1
    Dernier message: 27/09/2005, 10h00
  3. problème de cast!
    Par LaseLiep dans le forum Langage
    Réponses: 3
    Dernier message: 03/06/2005, 09h30
  4. Problème de cast/serialization/externalization ?
    Par Linlin dans le forum CORBA
    Réponses: 1
    Dernier message: 06/12/2004, 16h46
  5. [C#] Problème de casting de @IDENTITY
    Par bilb0t dans le forum Accès aux données
    Réponses: 7
    Dernier message: 03/09/2004, 09h42

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo