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 :

Passer de Java a C++


Sujet :

C++

  1. #1
    Membre actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2009
    Messages
    59
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2009
    Messages : 59
    Par défaut Passer de Java a C++
    Bonjour, merci de prendre du temps pour lire mon post.

    Je dois transcrire un programme que j'ai codé en Java en C++.
    Seulement petit problème je n'ai jamais touché à C++ de ma vie!
    C'est pourquoi je fais appelle à la fabuleuse communauté Developpez.com

    Voici la classe qui me donne le plus de difficulté :

    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
    public abstract class Prisonnier {
     
     
        private String name;
        private int annee;
        protected boolean coupPrecedentAdverssaire;
        protected int nbCoups;
        protected int score;
     
     
        public abstract boolean reponse();
     
     
        public Prisonnier(String nom) {
            name = nom;
        }
     
        public int getAnnee() {
            return annee;
        }
    }
    Plusieurs choses me trouble, comment traduire le abstract de la classe? des méthodes?

    Et également dans ma classe héritée :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    public class StrategieAvouer extends Prisonnier {
     
        public StrategieAvouer(String nom) {
            super(nom);
        }
     
        @Override
        public boolean reponse() {
            return true;
        }
    }
    Comment traduire le fait que je surcharge la méthode reponse()? et surtout, comment traduire : Merci de vos réponses.

  2. #2
    Membre confirmé
    Homme Profil pro
    Développeur .NET/C/C++
    Inscrit en
    Septembre 2007
    Messages
    71
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur .NET/C/C++
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Septembre 2007
    Messages : 71
    Par défaut
    Citation Envoyé par Reminouche Voir le message
    Bonjour, merci de prendre du temps pour lire mon post.

    Je dois transcrire un programme que j'ai codé en Java en C++.
    Seulement petit problème je n'ai jamais touché à C++ de ma vie!
    C'est pourquoi je fais appelle à la fabuleuse communauté Developpez.com

    Voici la classe qui me donne le plus de difficulté :

    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
    public abstract class Prisonnier {
     
     
        private String name;
        private int annee;
        protected boolean coupPrecedentAdverssaire;
        protected int nbCoups;
        protected int score;
     
     
        public abstract boolean reponse();
     
     
        public Prisonnier(String nom) {
            name = nom;
        }
     
        public int getAnnee() {
            return annee;
        }
    }
    Plusieurs choses me trouble, comment traduire le abstract de la classe? des méthodes?

    Et également dans ma classe héritée :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    public class StrategieAvouer extends Prisonnier {
     
        public StrategieAvouer(String nom) {
            super(nom);
        }
     
     
        public boolean reponse() {
            return true;
        }
    }
    Comment traduire le fait que je surcharge la méthode reponse()? et surtout, comment traduire : Merci de vos réponses.
    Commençons par le début, la déclaration de ta classe.
    En fait, tu n'as tout simplement pas à ajouter la directive abstract, le compilo déterminant cela tout seul.
    Pour tes méthodes, la déclaration d'une méthode abstraite se fait en ajoutant le mot-cle virtual et en ajoutant " = 0" à la fin de celle-ci.
    Cela donne :

    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
     class Prisonnier {
    private:
        std::string name;
        int annee;
    protected: 
        bool coupPrecedentAdverssaire;
        int nbCoups;
        int score;
    public:
        virtual bool reponse() = 0;
        Prisonnier(const std::string& nom) : name(nom)
        {
        }
        int getAnnee() const {
            return annee;
        }
    }
    Bon j'avoue, j'ai ajouté quelques autres concept tiré du C++ (comme les std::string, l'utilisation de reference ou la liste d'initialisation). Mais au moins comme cela tu prendra de suite les bonne habitude.

    Pour la classe héritée:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    class StrategieAvouer : public Prisonnier {
    public:
        StrategieAvouer(const std::string& nom) : Prisonnier(nom)
        {
        }
     
        @Override
        public bool reponse() {
            return true;
        }
    }
    Voilà

  3. #3
    Membre actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2009
    Messages
    59
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2009
    Messages : 59
    Par défaut
    Ok merci de ta réponse , j'ai quasiment tout comprit.

    Mis a part le constructeur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Prisonnier(const std::string& nom) : name(nom)
        {
        }
    Que tu me conseilles de mettre.

    Moi dans mon code C++ j'avais mit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Prisonnier(std::string);
    dans mon prototype

    et

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     Prisonnier::Prisonnier(std::string nom) : name(nom)
    {
    dans ma classe

    Lequel est le bon ?


    EDIT : Que signigie : " warning: `class Prisonnier' has virtual functions but non-virtual destructor| "

    Dernière question : j'ai une autre classe Match telle que :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class Match{
        private :
            int nbParties;
            Prisonnier p;
        public :
            Match(Prisonnier perso1);
            ~Match();
    };
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Match::Match(Prisonnier perso1) : p(perso1)
    {
    }
    J'ai une erreur de type : " cannot declare parameter `perso1' to be of type `Prisonnier'|" , pk cela ?

  4. #4
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Citation Envoyé par Reminouche Voir le message
    Lequel est le bon ?
    Le premier (avec le &) est un passage par référence. C'est un peu comme java il me semble : l'objet n'est pas copié, c'est une référence vers cet objet qui est transmise.
    Le second (sans le &) est un passage par valeur. Lors de l'appel du constructeur (ou de la fonction) un nouvel objet temporaire est créé, le paramètre est copié dans cet objet temporaire et finalement, c'est cet objet temporaire qui est donné à la fonction/constructeur.
    Lequel préférer ? Tout dépend. Et on entre dans les subtilités du C++... Il est évident que le passage par référence permet un passage de paramètre plus rapide car l'objet n'est pas recopié. Cependant le passage par valeur permet de bénéficier d'une optimisation des compilateurs C++ appelée (N)RVO qui consiste à 'factoriser' des objets transmis en cascade. De même, le passage par valeur est souvent plus efficace pour les types de base que le passage par référence. Histoire de ne pas trop se compliquer la vie, je te conseillerais de transmettre par référence constante les objets et par valeur les types de base. Puis d'entrer dans les subtilités plus tard.
    Encore quelques précisions :
    • Le passage par valeur : la modification du paramètre dans la fonction n'a pas d'impact pour le paramètre donné par l'appelant.
    • Le passage par référence constante : la modification du paramètre dans la fonction va provoquer une erreur de compilation.
    • Le passage par référence non constante : la modification du paramètre dans la fonction modifie le paramètre donné par l'appelant.

    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
    void valeur(int i_)
    {
       ++i_;
       std::cout<<"i dans valeur : "<<i_<<std::endl;
    }
    void reference_constante(int const &i_)
    {
       ++i_; // Erreur : vous ne pouvez pas assigner une variable const
       std::cout<<"i dans reference_constante : "<<i_<<std::endl;
    }
    void reference_non_constante(int &i_)
    {
       ++i_;
       std::cout<<"i dans reference_non_constante : "<<i_<<std::endl;
    }
    Si on supprimer la fonction reference_constante, et qu'on écrit :
    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
    #include <iostream>
     
    void valeur(int i_)
    {
       ++i_;
       std::cout<<"i dans valeur : "<<i_<<std::endl;
    }
    void reference_non_constante(int &i_)
    {
       ++i_;
       std::cout<<"i dans reference_non_constante : "<<i_<<std::endl;
    }
    int main()
    {
       int ici(42);
       std::cout<<"avant : "<<ici<<std::endl;
       valeur(ici);
       std::cout<<"après : "<<ici<<std::endl;
     
       std::cout<<"avant : "<<ici<<std::endl;
       reference_non_constante(ici);
       std::cout<<"après : "<<ici<<std::endl;
     
       return 0;
    }
    avant : 42
    i dans valeur : 43
    apres : 42
    avant : 42
    i dans reference_non_constante : 43
    apres : 43
    On obtient :

    Citation Envoyé par Reminouche Voir le message
    EDIT : Que signigie : " warning: `class Prisonnier' has virtual functions but non-virtual destructor| "
    La réponse est dans la F.A.Q. : en gros : ou ton destructeur est public et virtuel car tu peux détruire l'objet de façon polymorphe (c'est à dire avec sa classe de base) ou ton destructeur est protégé et non virtuel et tu interdis ainsi de détruire l'objet à partir d'une référence de sa classe de base.
    Citation Envoyé par Reminouche Voir le message
    J'ai une erreur de type : " cannot declare parameter `perso1' to be of type `Prisonnier'|" , pk cela ?
    Normalement tu as du déclarer Prisonnier dans un fichier d'en-tête .h (mettons Prisionner.h) et définir ses méthodes dans un fichier source .cpp.
    Lorsque tu as besoin d'utiliser la classe Prisionner, il faut rajouter #include "Prisonnier.h" pour indiquer au compilateur où trouver la déclaration du type Prisonnier.

    Je reviens sur l'abstract et quelques notions d'héritage et de virtualité.
    Commençons par deux définitions :
    -> Le type statique d'une variable est le type tel qu'il apparaît dans le code
    -> Le type dynamique d'une variable est le type possédé effectivement à l'exécution :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    class A{};
    class B : public A{};
    int main()
    {
       A a;
       B b;
       A &ra = a;
       A &rb = b;
       return 0;
    }
    Le type statique de a est A. Le type dynamique de a est A.
    Le type statique de b est B. Le type dynamique de b est B.
    Le type statique de ra est A. Le type dynamique de ra est A.
    Le type statique de rb est A. Le type dynamique de rb est B.

    On accède au type dynamique avec les références ou les pointeurs :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
       A a;
       B b;
       A a2 = b;
       A &ra = b;
       A *pa = &b;
    Le type statique de a est A. Le type dynamique de a est A.
    Le type statique de b est B. Le type dynamique de b est B.
    Le type statique de a2 est A. Le type dynamique de a2 est A. En fait, a2 est une copie de b et n'a plus rien à voir avec b.
    Le type statique de ra est A. Le type dynamique de ra est A.
    Le type statique de pa est A. Le type dynamique de pa est B.


    Par défaut, la fonction appelée pour un objet est celle définie dans son type statique :
    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 <iostream>
    class A{
    public:
       void qui_suis_je() const
       {
          std::cout<<"je suis un A"<<std::endl;
       }
    };
     
    class B : public A{
    public:
       void qui_suis_je() const
       {
          std::cout<<"je suis un B"<<std::endl;
       }
    };
     
    int main()
    {
       A a;
       a.qui_suis_je();
       B b;
       b.qui_suis_je();
       A &ra = a;
       ra.qui_suis_je();
       A &rb = b;
       rb.qui_suis_je();
     
       return 0;
    }
    Ce code produit comme résultat :
    je suis un A
    je suis un B
    je suis un A
    je suis un A
    Le mot clé virtual permet de dire que la fonction à prendre en compte est celle la plus spécialisée compte tenu du type dynamique de l'objet. Si on reprend notre exemple :
    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
    #include <iostream>
    class A{
    public:
       virtual void qui_suis_je() const
       {
          std::cout<<"je suis un A"<<std::endl;
       }
    };
     
    class B : public A{
    public:
       virtual void qui_suis_je() const
       {
          std::cout<<"je suis un B"<<std::endl;
       }
    };
     
    int main()
    {
       A a;
       a.qui_suis_je();
       B b;
       b.qui_suis_je();
       A &ra = a;
       ra.qui_suis_je();
       A &rb = b;
       rb.qui_suis_je();
     
       return 0;
    }
    On a alors :
    je suis un A
    je suis un B
    je suis un A
    je suis un B
    Toute les fonctions d'une classe peuvent être virtuelles à l'exception du constructeur (ça n'aurait pas vraiment de sens en fait).
    Donc le destructeur peut être virtuel. Ce qui permet que ce soit bien le destructeur le plus spécialisé qui est appelé lorsqu'on détruit une variable d'un type statique plus abstrait :
    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
    #include <iostream>
    class A{
    public:
       virtual ~A(){
          std::cout<<"destructeur de A"<<std::endl;
       }
    };
     
    class B : public A{
    public:
       virtual ~B(){
          std::cout<<"destructeur de B"<<std::endl;
       }
    };
     
    int main()
    {
       std::cout<<"Pour A : "<<std::endl;
       A *p_a = new A;
       delete p_a;
     
       std::cout<<"Pour B : "<<std::endl;
       A *p_b = new B;
       delete p_b;
       return 0;
    }
    Pour A :
    destructeur de A
    Pour B :
    destructeur de B
    destructeur de A
    Si le destructeur n'avait pas été virtuel, alors le comportement aurait été indéterminé : cela aurait pu appeler que le destructeur de A ou planter ou faire le café.

    Une classe dérivant une classe de base n'est pas obligée de spécialiser les méthodes virtuelles de la classe de base. Le comportement est alors celui de la dernière spécialisation :
    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
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    #include <iostream>
    class A{
    public:
       virtual void qui_suis_je()const
       {
          std::cout<<"je crois que je suis un A"<<std::endl;
       }
       virtual ~A(){}
    };
     
    class B : public A{
    public:
       virtual void qui_suis_je()const
       {
          std::cout<<"je crois que je suis un B"<<std::endl;
       }
       virtual ~B(){}
    };
     
    class C : public A
    {
    };
     
    class D : public B
    {
    };
     
    void qui_es_tu(A const&ra_)
    {
       ra_.qui_suis_je();
    }
    int main()
    {
       A a;
       qui_es_tu(a);
       B b;
       qui_es_tu(b);
       C c;
       qui_es_tu(c);
       D d;
       qui_es_tu(d);
     
       return 0;
    }
    Produit :
    je crois que je suis un A
    je crois que je suis un B
    je crois que je suis un A
    je crois que je suis un B
    Lorsqu'on veut forcer la spécialisation par une classe dérivée, on adjoint '=0' à la méthode :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class A{
    public:
       virtual void qui_suis_je()const = 0;
       virtual ~A(){}
    };
    On dit que qui_suis_je est une méthode abstraite. Une classe qui possède au moins une méthode abstraite est une classe abstraite. Une classe abstraite ne peut être instanciée :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    A a;// --> 'A'*: impossible d'instancier une classe abstraite
    Une classe dérivant de A devra spécialiser les méthodes abstraites pour pouvoir être instanciée Sans quoi elle sera elle aussi abstraite :
    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
    #include <iostream>
    class A{
    public:
       virtual void qui_suis_je()const = 0;
       virtual ~A(){}
    };
     
    class B : public A{
    public:
       virtual void qui_suis_je()const
       {
          std::cout<<"je crois que je suis un B"<<std::endl;
       }
       virtual ~B(){}
    };
     
    class C : public A
    {
    };
     
    class D : public B
    {
    };
     
    int main()
    {
       A a; // Erreur A est une classe abstraite
       B b; // OK B spécialise bien qui_suis_je()
       C c;// Erreur C ne spécialise pas qui_suis_je() donc conserve le caractère abstrait de A
       D d; // OK D ne spécialise pas qui_suis_je() mais bénéficie de la spécialisation de cette méthode par B.
     
       return 0;
    }
    Comme le destructeur peut être virtuel, il peut aussi être abstrait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    class A{
    public:
       virtual ~A()=0;
    };
    C'est souvent le meilleur moyen d'indiquer qu'une classe est abstraite :
    -> car ta classe peut ne pas avoir besoin de spécifier d'autres méthodes abstraites
    -> car si les autres méthodes de la classe peuvent varier en fonction de l'évolution du projet (par exemple, on décide de ne plus la rendre virtuelle), le destructeur reste stable. Et on ne risque pas de perdre cette info suite à une inattention dans une évolution.

    Deux derniers points :
    -> Même si les méthodes abstraites peuvent avoir une définition (un corps), en général ce n'est pas le cas. On se rend compte rapidement qu'il s'agit souvent d'une conception bancale.
    -> Exception au dernier point : le destructeur même abstrait doit être défini :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    class A{
    public:
       virtual void qui_suis_je()const = 0; // pas obligé de le définir
       virtual ~A()=0{} // obligé de le définir
    };

Discussions similaires

  1. Passer de Java 6 à Java 5
    Par rwikus09 dans le forum Eclipse Java
    Réponses: 0
    Dernier message: 08/04/2011, 03h32
  2. Réponses: 3
    Dernier message: 10/09/2010, 14h06
  3. Valeur à passer en Java
    Par Lolitaaa dans le forum Général Java
    Réponses: 5
    Dernier message: 10/12/2009, 14h11
  4. passer de java à c#
    Par the sun dans le forum C#
    Réponses: 3
    Dernier message: 05/06/2007, 13h15
  5. Passer De Java à C
    Par raph707 dans le forum C
    Réponses: 11
    Dernier message: 27/02/2007, 18h36

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