Download Fiche de td TP d’introduction à la programmation objet orientée en c++ and more Exercises Object Oriented Programming in PDF only on Docsity! TD/TP de C++ Numéro 1 Classes, Objets, Constructeurs, Destructeurs, Variables et Méthodes d’Instance, Variables et Méthodes de Classe, E/S Standard, Visibilité et Pointeurs d’Objet Questions de Cours 1) Quelle est la différence entre la notion de classe et la notion d’objet ? 2) Définir les expressions suivantes : (a) variable de classe, (b) variable d’instance, (c) méthode de classe, (d) méthode d’instance, (e) constructeur, (f) accesseur en modification, (g) accesseur en consultation, (h) instance d'une classe. 3) Donner la signification de la visibilité public quand elle est affectée à une méthode. 4) Même question qu’en 3) avec la visibilité private. 5) Donner la signification de la visibilité public sur une variable d’instance ou de classe. 6) Quelle est la signification du mot clé this dans un constructeur ? 7) Quelle est la signification du mot clé this dans une méthode d’instance ? 8) En C, les deux routines malloc et free sont utilisées respectivement pour l’allocation dynamique et la libération dynamique. Peut on utiliser ces routines en C++ ? Quels sont les deux routines utilisées en C++ ? 9) Quels sont les deux opérateurs d'accession à une variable d'instance et de classe ? 10) Quels sont les deux opérateurs d'envoi de message à un objet ou à une classe ? 11) On sait que les langages Pascal, C et Fortran sont totalement compilés. On sait que les langage Basic, sql et shell sont totalement interprétés. On sait que le langage java est partiellement compilé et interprété. Qu’en est il du langage C++ ? Problème 1 : Analyse de Code, Correction de Code et Enrichissement de Code Partie I : Analyse du Code de la Classe Point 1) Y a t’il un constructeur de copie (Page 55 du support de cours)? 2) Citer les variables d’instance. Y a t’il une variable de classe ? 3) Citer les méthodes d’instance. Y a t’il une méthode de classe ? 4) Quel est le rôle du champ nombre_points ? 5) Quel est le rôle de la méthode affichage ? 6) Quel est le rôle de la méthode lire_point ? 7) Citer les deux accesseurs en consultation. 8) Citer les deux accesseurs en modification. 9) Pourquoi la méthode d’instance getX() a le droit d'accéder directement à l’abscisse d’un point ? 10) Pourquoi la méthode d’instance lire_Point() a le droit d’appeler le constructeur à deux arguments ? 11) Peut-on appeler le constructeur à deux arguments de Point dans le fichier test_point.cxx ? Partie II : Analyse et Correction du Code de la Classe Cercle 1) Citer les méthodes qui sont codées inline. 2) Donner le rôle de la méthode affichage. 3) Même question qu’en 2) pour la méthode lire_Cercle. 4) Si la visibilité de lire_Point dans la classe Point était private, la ligne gras de la méthode lire_Cercle serait elle correcte ? Peut-on modifier directement l’abscisse d’un point dans lire_Cercle (pt.x=4) ? 5) Ecrire un bout de code permettant de tester les méthodes définies dans la classe Cercle ? 6) On rappelle que dans un constructeur, on initialise d’abord les variables d’instance de manière automatique avant de commencer l’exécution des instructions dudit constructeur. Cette initialisation fait appel aux constructeurs par défaut (sans argument) des variables d’instance qui sont des objets. Par exemple, avant d’exécuter le corps d’un constructeur de Cercle, on initialise automatiquement le centre en exécutant le constructeur sans argument de Point puis on initialise le rayon. Si on supprime dans point.h et point.cxx le constructeur sans argument, un constructeur de Cercle peut-il s’exécuter correctement ? 7) Considérons le constructeur en gras. (7.1) Peut on remplacer la déclaration en gras par Point pt() ? (7.2) Peut-on remplacer le corps de ce constructeur par « (this->centre).setX(x); (this->rayon).setY(y); » ? 8) Peut-on modifier directement le rayon d’un cercle dans test_cercle.cxx (c.rayon=1.0) ? 1 // Fichier d’entête point.h class Point { private: float x ; float y ; static int nombre_points; Point(float a, float b) ; public : ~Point() ; //destructeur Point() ; Point(float a) ; Point(Point &p); float getX() ; float getY() ; void setX(float a) ; void setY(float b) ; void affichage(); static Point lire_Point() ; static int getNombre_points() ; }; // Fichier d’implémentation point.cxx #include "point.h" #include <iostream> #include <stdio.h> using namespace std; int Point::nombre_points=0; Point ::~Point() {} Point ::Point( ) { (*this).x=0 ; (*this).y=0 ; nombre_points++ ; } Point ::Point(float a, float b) { (*this).x=a ; (*this).y=b ; nombre_points++ ; } Point::Point(float a) { (*this).x=a ; (*this).y=a; nombre_points++ ; } Point::Point(Point &p){ this->x=p.x; this->y=p.y ; nombre_points++ ; } float Point::getX() {return (*this).x ; } float Point::getY() {return (*this).y ; } void Point::setX(float a) {this->x=a ; } void Point::setY(float b) {this->y=b ; } void Point::affichage(){ cout << "("<< (*this).x<<"," ; cout <<(*this).y<< ")" ; } // Fichier d’entête cercle.h #include "point.h" class Cercle { private: static int nombre_cercles; Point centre ; float rayon ; public : static const float PI ; //Constante de Classe Cercle(float x, float y, float ray) ; Cercle(float x, float ray); Cercle(Point center, float ray); Cercle(); ~Cercle() ; float getRayon() {return this->rayon ; } Point getCentre() {return this->centre ; } void setRayon(float rayon) {this->rayon=rayon ; } void setCentre(Point centre) {this->centre=centre ; } void setCentre(float a, float b) ; void affichage() ; static Cercle lire_Cercle() ; }; // Fichier d’implémentation cercle.cxx #include "cercle.h" #include <iostream> using namespace std; float const Cercle::PI=3.14 ; //Constante de Classe int Cercle::nombre_cercles=0; Cercle::~Cercle() {} ; Cercle::Cercle() { this->rayon=1; (this->centre).setX(0); (this→centre).setY(0); nombre_cercles++ ; } Cercle::Cercle(float x, float y, float ray) { Point pt; pt.setX(x); pt.setY(y); this->centre=pt; this->rayon=ray ; nombre_cercles++ ; } Cercle::Cercle(float x, float ray) { Point pt(x); this->centre=pt; this->rayon=ray ; nombre_cercles++ ; } Cercle ::Cercle(Point center, float ray) { this->centre=center ; this->rayon=ray ; nombre_cercles++ ; } 2 1) Un premier constructeur sans argument, un deuxième constructeur qui prend quatre arguments ( l’abscisse du point supérieur gauche, l'ordonné du point supérieur gauche, la largeur et la longueur) et un troisième constructeur qui prend un rectangle (constructeur de recopie). On rappelle que le constructeur par défaut sert à initialiser une variable objet à la déclaration et à initialiser les sous-objets d’un objet composite juste avant l’exécution du corps du constructeur de l’objet composite. Le constructeur de recopie est utilisé pour passer des objet par valeur aux fonctions et pour retourner un objet avec l’instruction return dans une fonction. Le constructeur de recopie par défaut recopie membre à membre des attributs de l ‘objet. Ceci n’est pas convenable si la classe dispose d’attributs dynamiques. En cas d’attributs dynamiques, le programmeur devra définir un constructeur de recopie approprié. 2) Les accesseurs en consultation et en modification. 3) Une méthode d'instance float perimetre() qui invite le rectangle récepteur du message à calculer et à retourner son périmètre. 4) Une méthode d'instance float surface() qui invite le rectangle récepteur du message à calculer et à retourner sa surface. 5) Une méthode d’instance int operator==(Rectangle r) qui invite le rectangle récepteur du message à dire s’il est égal ou non au rectangle r porté par le message equals. Deux rectangles sont égaux s'ils ont le même point supérieur gauche, la même largeur et la même longueur. 6) Une méthode d'instance void afficher() qui invite l'objet (de la classe Rectangle) récepteur du message à afficher sa description. Exemple d’affichage : Rectangle[(4,5), 5000, 10000]. Voici une séquence d’instructions qui réalise cela (voir page 63 du support). En C++, cin désigne le flux d’entrée et cout désigne le flux de sortie (#include <iostream>). On pourrait remplacer cout par std::cout. cout << "Rectangle[" ; // cout << "Rectangle[" << endl ; fait un passage à la ligne. (*this).psg.affichage ; cout << "," << (*this).largeur << "," << (*this).longueur << "]" 7) Une méthode de classe static float perimetre(Rectangle r) qui invite la classe Rectangle réceptrice du message à calculer et à retourner le périmètre du rectangle porté par le message. Les concepts de variable de classe et de méthode de classe sont décrites à la page 43 du support de cours. 9) Une méthode de classe qui invite la classe Rectangle réceptrice du message à calculer et à retourner la surface du rectangle porté par le message. 10) Une méthode d'instance int estDans(Point p) qui invite l’objet Rectangle récepteur du message à retourner TRUE si le point porté par le message est dans le rectangle et FALSE sinon. 11) Une méthode d'instance int estInclus(Rectangle r) qui invite l’objet Rectangle récepteur du message à retourner TRUE si le rectangle r porté par le message est inclus dans le rectangle récepteur du message et FALSE sinon. B) Définir le contenu du fichier d’implémentation rectangle.cxx. C) Proposer une méthode principale qui teste toutes les méthodes implémentées. Indication : Pour répondre aisément à certaines questions, il faudrait introduire les méthodes d’instance suivantes : (1) retourner le point inférieur gauche (get_pig), (2) calculer et retourner le point supérieur droit (get_psd), (3) calculer et retourner le point inférieur droit (get_pid). Exercice 3 : Les Elèves Un élève est décrit par un matricule, nom, une note en mathématique, une note d’informatique et une note de physique. Chaque élève possède un matricule généré automatiquement qu’on ne peut pas changer et que deux élèves possèdent des matricules distincts. Pour cela on introduit une variable de classe appelée nbreCreation initialisée à 0 qui contiendra à chaque instant le nombre d'élève déjà crées. Dans chaque constructeur, la valeur de nbreCreation est affectée comme matricule de l'objet Eleve en cours de création puis incrémentée de 1. On rappelle que les concepts de variable de classe et de méthode de classe sont décrites à la page 43 du support de cours. Ne nom de l’étudiant ne peut changer. De mémé le matricule de l’étudiant ne peut changer. En C++ il existe deux manières de gérer les chaînes de caractères : Un tableau de caractères comme en c : char ch[50]; 5 Un objet : string st; (#include <string>) Il faudrait déclarer le champ nom comme un string. A) Expliquer pourquoi on ne faut pas prévoir d’accesseur en modification sur le nom et ni sur le matricule. B) Définir le contenu du fichier d’entête eleve.h en affectant la visibilité public à toutes les méthodes et la visibilité private à toutes les variables d’instance sachant que les spécifications sont : 1) Un constructeur à un argument qui prend en entrée le nom de l’élève (un objet string) et un autre à cinq arguments (qui prend en entrée le nom et les notes des trois matières). 2) Les accesseurs en consultation et en modification par matières. Un accesseur en consultation sur le nom et un accesseur en consultation sur le matricule. 3) Une méthode d'instance void affichage() qui invite l'objet Elève récepteur du message à afficher sa description. Par exemple Eleve[mathématiques 15, informatique 18, physique 15]. 4) Une méthode d'instance float moyenne() qui invite l'objet Elève récepteur du message à calculer et retourner retourne sa moyenne. 7) La méthode d'instance public int operator==(Eleve &e) invite l'objet récepteur du message à calculer et à retourner TRUE s'il est égal à l'objet porté par le message et FALSE sinon. Deux élèves sont égaux s'ils ont le même matricule. 8) Une méthode de classe static Eleve lire() qui lit le nom d’un élève au clavier, crée un objet Elève et retourne cet objet. On rappelle que en C++, cin désigne le flux d’entrée et cout désigne le flux de sortie. Eleve *pt_eleve ; string name ; cout << "Entrer le nom de l’élève"; cin >> name ; pt_eleve=new Eleve(name) ; // Page 15 du support de cours return *pt_eleve ; B) Définir le contenu du fichier d’implémentation eleve.cxx. C) Proposer une méthode principale qui teste toutes les méthodes implémentées. Exercice 4: Les Segments Un segment est décrit par deux points. On utilisera la classe Point définie en dimension 2 (2D). A) Définir le contenu du fichier d’entête segment.h en affectant la visibilité public à toutes les méthodes et la visibilité private à toutes les variables d’instance sachant que les spécifications sont : 1) Un premier constructeur qui construit un segment à partir de deux points et un deuxième constructeur qui prend en entrée un segment. 2) Les accesseurs en modifications et en consultation. 3) Une méthode d'instance void affichage() qui invite l'objet Segment récepteur du message à afficher sa description. Par exemple Segment[(4,5), (10,15)]. 4) La méthode d'instance int operator==(Segment &s) invite l'objet récepteur du message à à retourner TRUE s'il est égal à l'objet porté par le message et FALSE sinon. 5) Une méthode d'instance appelée longueur() qui retourne la longueur (distance euclidienne) du segment récepteur du message. On rappelle que sqrt(x) (ou $_:sqrt(x)) retourne la racine carrée de x (page 45 du support) . 6) Une méthode d'instance int appartient(Point p) qui retourne TRUE si le point porté par le message appartient au segment récepteur du message et FALSE sinon. Un point p appartient à un segment si la somme des deux distances qui le sépare aux deux extrémités du segment est égale à la longueur du segment. 7) Une méthode d'instance int estInclus(Segment s) qui dit si le segment porté par le message est inclus dans le segment récepteur du message. Le segment s est inclus dans le segment this si les deux extrémités de s appartiennent à this. B) Définir le contenu du fichier d’implémentation segment.cxx. C) Proposer une méthode principale qui teste toutes les méthodes implémentées. 6