Docstoc

concepts

Document Sample
concepts Powered By Docstoc
					4.  CONCEPTS DE LA PROGRAMMATION ORIENTEE OBJET : LES CLASSES ET LES
OBJETS.............................................................................................................................................................3
4.1          Programmation traditionnelle en C.......................................................................................................3
4.2          Programmation objet : l'encapsulation. ................................................................................................5
4.3          Définitions. ...........................................................................................................................................5
4.4          Améliorations 1 : private, accesseur. ....................................................................................................7
4.5          Amélioration 2 : Fonctions membres constructeur et destructeur ........................................................9
4.6          Autres éléments d'une classe : ............................................................................................................11
4.7          Définition et utilisation des objets ....................................................................................................12
4.8          Organisation pratique des fichiers ......................................................................................................13
4.9          exercice : ............................................................................................................................................14
5.      CONSTRUCTION DES OBJETS .......................................................................................................15
5.1          Classe de mémorisation des objets. ....................................................................................................15
5.2          Constructeur par défaut. .....................................................................................................................15
5.3          Constructeur de recopie. .....................................................................................................................17
5.4          Cas des objets avec des objets membres. ...........................................................................................19
5.5          initialisation des objets ( <> affectation ). ..........................................................................................19
5.6          Affectation d’objets. ...........................................................................................................................19
5.7          Tableaux d’objets. ..............................................................................................................................20
6.      S AMIS. ..................................................................................................................................................21
6.1          Fonction amie. ....................................................................................................................................21
6.2          Classe amie.........................................................................................................................................21
    4. Concepts de la programmation orientée objet : les classes et
                             les objets


4.1      Programmation traditionnelle en C
soit le programme suivant :
#include <iostream.h>

struct Personne { // une personne est décrite par son nom et sa societe
    char nom[ 20 ] ;
    char societe[ 30 ];
};

void presente( struct Personne p )
//-----------------------------------------------------------------
// affiche la description d'une personne
{
       cout << "je m'appelle " << p.nom << endl ;
       cout << "je travaille à " << p.societe << endl ;
}

int main()
{
     // on definit une variable individu qui décrit une personne
     struct Personne individu ;                 // struct inutile en C++

      // on initialise cette variable
      strcpy( individu.nom, "Durand" );
      strcpy( individu.societe, "Thomson" );

      // on affiche la description de la variable individu
      presente( individu );
      return 0 ;
}

Cet exemple montre l'implémentation et l'utilisation d'un type Personne.
Quelques inconvénients :
  5. séparation des données (nom et société) et des
traitements (presente() ) Le type abstrait Personne est
     aussi bien caractérisé par ses données et ses
                      traitements.

   Les contrôles sont difficiles à assurer : on peut afficher une personne sans avoir donné une valeur
    à ses données (variable non initialisée), on peut changer le nom d'une personne (toutes les
    données sont accessibles à l'utilisateur de la structure) !...
                  6. Programmation objet : l'encapsulation.

Cahier des charges d'un type Personne :
 Une personne est décrite par 2 informations :
    son nom
 la société où elle travaille.
 Une personne est capable de se présenter en affichant ses données.

class Personne { // une personne est décrite par son nom, sa societe, son comportement
public :
    char nom[ 20 ] ;
    char societe[ 30 ];
    void presenteToi( ) {
         cout << "je m'appelle " << nom << endl ;
         cout << "je travaille à " << societe << endl ;
    }
};

int main()
{
     // on definit une variable individu qui décrit une personne
     Personne individu ;

       // on initialise cette variable
       strcpy( individu.nom, "Durand" );
       strcpy( individu.societe, "Thomson" );

       // on demande à individu de se présenter
       individu.presenteToi( );
       return 0 ;
}

Les changements :
 Les données et les comportements sont rassemblés - encapsulés - dans une même entité. L'objet est défini
   par ses données et par son comportement.
 La fonction presenteToi() n'a pas besoin de paramètres. Les champs nom et societe sont directement
   accessibles à l'intérieur de la classe.
 L'instruction : individu.presenteToi( ); représente l'envoi d'un message à l'objet individu. Cet envoi de
   message déclenche le traitement demandé. Ce traitement est connu de l'objet.

6.1       Définitions.
 Une classe est analogue à un type (extension du type struct du C).

 Un objet est une instance (une entité identifiable, un exemplaire) d’une classe. Un objet est analogue à
  une variable. La création d'un objet est appelée une instanciation.

Une classe comprend
 des données (les données membres, des champs). Les variables sont des variables d'instances 1.
 des fonctions membres pour manipuler les données membres. Les fonctions membres décrivent le
  comportement des objets. (Les méthodes).

                                               l’encapsulation:
                              Regroupement dans une même structure des données
                          et du comportement (fonctions qui manipulent ces données).

1
    on verra plus tard des variables de classe.
                                                                  p1, un objet Personne

                                                        Durand            Thomson
               La classe Personne                        nom               societe


                 nom       societe


                                          deux instanciations
                cout << ... ;
                cout << ....;
                   presenteToi()                                  p2, un autre objet Personne

                                                       Dupond              ISAIP
                                                         nom               societe



class NomClasse                   // nom de la classe
{
public :                          // spécificateur d'accès
    int x, y ;                    // variables membres
    char s[ 10 ] ;
    void f( ) ;                            // fonctions membres
    int g( ) ;
};
Une classe se définie comme une structure.

 A partir d'une classe on peut créer autant d'objets que nécessaire. Chaque objet contient ses données
  membres (variables d'instances), mais le comportement n'est défini qu'une seule fois dans la classe pour
  tous les objets membres de la classe.

 Pour déclencher un traitement, un comportement, il faut envoyer un message à un objet.

 Les membres d'un objet ont un spécificateur d'accès : ici public. Public veut dire que tous les membres
  sont accessibles de l'extérieur de la classe.
6.2       Améliorations 1 : private, accesseur.
Mais Les contrôles sont toujours difficiles à assurer : on peut afficher une personne sans avoir donné une
valeur à ses données (variable non initialisée), on peut changer le nom d'une personne (toutes les données
sont accessibles à l'utilisateur de la structure) !...

Nouveau cahier des charges d'un type Personne :
1. Une personne est décrite par 2 informations : son nom et sa société
2. Une personne a toujours un nom, ce nom ne peut pas changer, tous les caractères sont en majuscule, il
   comporte 20 caractères max.
3. Une personne peut ne pas être associée à une société (non salariée ).
4. S'il existe, le nom de la société comporte 30 caractères max et est en majuscule.
5. Une personne peut changer de société.
6. Une personne est capable de se présenter en affichant ses données.

 Nouveau spécificateur d'accès : private :
   Les membres d'accès privés sont inaccessibles en dehors de la classe. Il ne sont accessibles que par les
   membres de la classe.
Pour pouvoir accéder aux membres privés il faut ajouter des fonctions membres publics.

class Personne { // une personne est décrite par son nom et sa societe
private :
     char nom[ 20 + 1 ] ;                          // membres privés
     char societe[ 30 + 1 ] ;
     char *majuscule( char * ) ;
public :                                 // membres publics
     void initNom( char *nm )
          { strncpy( nom, majuscule( nm ), 20 ) ; }
     void initSociete( char *soc )
          { strncpy( societe, majuscule( soc ), 30 ) ; }
     void init( char *nm, char *soc = "?" ) ;
     void presenteToi() ;
};

#include <iostream.h>
#include <ctype.h>
#include <string.h>

char *Personne :: majuscule( char *texte )
//-----------------------------------------------------------------
{
       int longueur = strlen( texte ) ;
       for( int i = 0; i < longueur; i++ ) texte[ i ] = toupper( texte[ i ] ) ;
       return texte ;
}

void Personne :: init( char *nm, char *soc )
//-----------------------------------------------------------------
// initialise les membres de la personne
// mets les noms en majuscule
// initialise par défaut la société à ? si pas défini
{
       initNom( nm );
       initSociete( soc );

}
void Personne :: presenteToi( )
//-----------------------------------------------------------------
{
       cout << "je m'appelle " << nom << endl ;
       if( strcmp( societe, "?" ) != 0 )
             cout << "je travaille à " << societe << endl ;
       else
             cout << "je ne suis pas dans une societe" << endl ;
}

int main()
//========================================================
{
     Personne individu ;

     individu.init( "DuPond", "Renault" );
     individu.presenteToi();

     individu.init( "Durand" );
     //    strcpy( individu.nom, "Durand" ); est maintenant impossible
     individu.presenteToi();
     return 0 ;
}

6.2.1     remarques :
 On peut trouver des variables membres et des fonctions membres privées.

 Les membres d’une classe peuvent être des variables, des constantes, des fonctions. des éléments de type
  prédéfini ou défini par l’utilisateur, d’autres objets, des déclarations de type ...

 Les membres d’une classe peuvent être privés ou publics. (private, public)
       privés : ils ne sont connus et utilisables directement que par les objets de la classe
       publics : ils sont connus et utilisables par tout utilisateur

 Par défaut les membres sont privés.

 Les fonctions privées sont réservées à un usage interne à la classe.

 Les fonctions peuvent être
       soit déclarées dans la classe et définies en dehors de la classe,
       soit déclarées et définies en même temps dans la classe.

 :: opérateur de (résolution de) portée. Pour préciser à quelle classe appartient la fonction.

 Les fonctions définies dans la classe sont inline par défaut. Elles sont en général petites. En général on
  définit à l'intérieur les fonctions membres très petites ( une ligne ).

 Toutes les fonctions membres d’un objet donné de la classe ont accès à tous les membres de cet objet
  (données ou fonctions)

                                            initNom()
                                                                                 nom
                                           initSociete()
                                         L'abstraction des données :
                              La structure exacte d'une donnée est cachée.
                        On peut utiliser un objet sans connaître sa structure interne.

                        Les données privées forment l'implémentation de la classe
                 les données publiques constituent l'interface entre l'objet et les utilisateurs

6.2.2   Accesseur ( sélecteur, manipulateur ).
Accesseur : fonction membre publique qui permet d'accéder aux variables d'instances privées.


Une variable d'instance privée peut :
 n'avoir aucun accesseur : c'est une variable d'implémentation dont l'existence n'est pas forcément connue
  par l'utilisateur qui ne peut ni la consulter ni la modifier.
 Avoir un accesseur en consultation : l'utilisateur de la classe peut consulter la variable d'instance mais
  ne peut pas la modifier.
 Avoir deux accesseurs, l'un en consultation, l'autre en modification : l'utilisateur de la classe peut
  consulter la variable d'instance et la modifier.

class Personne {
private :
     char nom[ 20 + 1 ] ;                      // membres privés
     char societe[ 30 + 1 ] ;
     char *majuscule( char * ) ;
public :                                // membres publics
     void initNom( char *nm ) { strncpy( nom, majuscule( nm ), 20 ) ; }
     void initSociete( char *soc ) { strncpy(societe, majuscule( soc ), 20 ) ; }
     void init( char *nm, char *soc = "?" ) ;
     void presenteToi( ) ;
     char *sonNom( char *nm) { return strcpy( nm, nom ) ; }
};

class Complex
{
    double x, y;
public :
    void init( double xx, double yy ) ; // accesseur en modification
    double &X( ) { return x; }          // accesseur en consultation et modification
    double &Y( ) { return y ; }
    double module() { return sqrt( x*x + y*y ) ; }
};

6.3      Amélioration 2 : Fonctions membres constructeur et destructeur

6.3.1   fonctions membres constructeur.
class Personne {
private :
     char nom[ 20 + 1 ] ;                       // membres privés
     char societe[ 30 + 1 ] ;
     char *majuscule( char * ) ;
     void initNom( char *nm ) { strncpy( nom, majuscule( nm ), 20 ) ; }
public :                                // membres publics
     Personne( char *nm, char *soc = "?" ) ; // fonction constructeur
     void initSociete( char *soc ) { strncpy( societe, majuscule( soc ), 20 ) ; }
     void presenteToi() ;
     char *sonNom( char *nm) { return strcpy( nm, nom ) ; }
};
 Fonction membre appelée automatiquement juste après toute création d’un objet. (après l’allocation de
  l’espace mémoire destiné à l’objet)
 Possède le même nom que la classe.
 N’a pas de type de retour.
 Le constructeur permet d'initialiser un nouvel objet.
 Il peut servir à initialiser l’objet au moment de sa création. (c’est sa fonction principale pour le
  programmeur).
 On peut définir plusieurs constructeurs.

Les valeurs d’initialisation sont mentionnées :
1. entre parenthèses après le nom de l’objet lors de sa définition.
2. en utilisant le signe = suivi explicitement de l’appel du constructeur
3. en utilisant le signe = suivi d’une valeur d’initialisation si le constructeur ne peut accepter qu’un seul
   paramètre.

Personne p1 ("Durand", "Renault" );
Personne p2 = Personne("Durand", "Renault");
Personne p3( "Durand" );                      // équivalent à p3("Durand", "?")
Personne p4 = Personne("Durand" );            // équivalent à p4("Durand", "?")
Personne p5 ;                       // illégal pas de constructeur sans paramètre
Personne p6 = "Durand";                       // équivalent à p6("Durand", "?") quand il y
aun seul paramètre


Même principe pour des objets dynamiques:

Complex *z1 = new Complex; // illégal
Complex *z2 = new Complex(1, 2);

 On peut définir plusieurs constructeurs avec des paramètres différents.


6.3.2    Fonction membre destructeur
class Tableau
{
    int *ptr;
public :
    Tableau ( ) { ptr = new int [ 100 ] ; }
    ~Tableau ( ) { delete [ ] ptr ; }
};

 Fonction membre appelée automatiquement juste avant toute destruction d’objet. (Avant la libération de
  la mémoire allouée).
 Possède le même nom que la classe précédée de ~ (tilda) (alt 126).
 N’a ni paramètre ni type de retour.
 Une classe ne peut posséder qu’un seul destructeur.
 Un destructeur sert principalement à nettoyer la mémoire quand l’objet possède des données allouées
  dynamiquement.
6.4     Autres éléments d'une classe :

6.4.1   Membres constants
class Tableau
{
    const int taille;            // pas d'initialisation ici
    int *ptr;
public :
    Tableau ( int n ) : taille( n ) { ptr = new int [ taille ] ; }
    ~Tableau ( ) { delete [ ] ptr ; }
};

 L’initialisation d’un membre constant se fait sur l’entête de chaque constructeur.
 Il s'agit d'une constante pour chaque objet, pas pour la classe.

6.4.2   Fonctions constantes : fonctions de consultation
class Complex
{
    double x, y;
public :
    Complex( double xx, double yy ) ;
    double X( ) const { return x ; }
    double Y( ) const { return y ; }
    void annule( ) { x = y = 0 ; }
};

 Ce sont des fonctions qui ne modifient pas l’état d’un objet : fonctions de consultation ( ou accesseur de
   consultation ).
on obtient
const Complex z( 1, 2 );

double x = z.X( );
z.annule( ) ;                      // erreur à la compilation.

 sur un objet constant on ne peut appeler que des fonctions constantes.

6.4.3   Membres statiques

Class Point
{
    static int nbPoint;
    int x, y;
public :
    Point( int xx, int yy ) { x = xx; y = yy; nbPoint++ ; }
    ~Point( ) { nbPoint-- ; }
    ...
};

int Point :: nbPoint = 0;          // déclaration obligatoire à l’extérieur de la classe
                                   // en global et initialisation

 Membres partagés par tous les objets d’une même classe : variables globales à la classe.
 initialisation au niveau global, pas dans un contructeur pour un objet donné.
 Une variable statique est une variable de classe alors que x et y sont des variables d’instances.
6.4.4    Fonctions statiques
Class Point
{
    static int nbPoint;
    int x, y;
public :
    Point( int xx, int yy ) { x = xx; y = yy; nbPoint++ ; }
    ~Point( ) { nbPoint-- ; }
    static int litNbPoint ( ) { return nbPoint ; }
    ...
};

   De la même façon une fonction statique est indépendante de tout objet.
   Une fonction statique est une fonction de classe.
   Une fonction statique n’a accès qu’aux membres statiques ( de classe ).
   Un objet a accès à ses membres propres et aux membres statiques.

int nb = Point :: litNbPoint ( ) ;         // de préférence
int nb = objetPoint.litNbPoint( ) ;        // moins naturel
 Les fonctions de classe (publiques) ne dépendant pas d’un objet particulier peuvent être appelées même si
    aucun objet n’a encore été créé.

6.4.5    Le pointeur this
 Toute fonction membre (non statique) dispose implicitement d’un pointeur sur l’objet courant
  manipulé par la fonction : ce pointeur est nommé this.
 De type const C * const

class Complex
{
    int x, y;
public :
    int &X() { return x ; }                      // équivalent à { return this->x ; }
    int &Y() { return y ; }                      // équivalent à { return this->x ; }
    Complex( int x, int y ) { this->x = x; this->y = y ; }
    void affiche() { cout << "x = " << x << "y = " << y
                       << " adresse de la variable = " << this ; }
};

ici this est de type Complex *

6.5      Définition et utilisation des objets
Les objets sont des variables du type de la classe, ce sont des instances de la classe.
Les objets se définissent et se manipulent comme des variables de type structure.
Definition = instanciation.

Complex z, *pz;             // les membres de z sont définis par le constructeur
double x, y, rho;

x = z.X( ) ;
y = z.Y( ) ;
rho = pz->module( );        // ou (*pz ).module( ) ; à éviter

z.x = 2.0 ;                          // erreur à la compilation
class Rectangle
{
    unsigned h, l;                  // membres privés
    unsigned c; // couleur
    void modifie( int, int );
public :
    Rectangle( unsigned haut = 0, unsigned larg = 0, unsigned col = NOIR );
    unsigned hauteur( );
    unsigned largeur ( );
    unsigned couleur ( );
    void dessine ( );
    void aggrandit( int )
    void deplace( int , int )
};

      Rectangle r;
      unsigned hauteur, largeur, couleur;
      largeur = r.l ;                 // erreur à la compilation
      largeur = r.largeur();
      r.h = 10;                       // erreur à la compilation
      r.modifie( 5, 8 ) ;             // erreur à la compilation
      r.deplace( 5, 8 );

 On peut faire des affectations entre objets comme entre des structures. Il y a alors recopie des valeurs de
    tous les champs de données.
Les fonctions ne sont pas copiées, elles sont définies une seule fois et appartiennent à tous les objets de la
classe.

Complex z1, z2;

z1 = z2;        ; z1 et z2 ont les mêmes valeurs pour x et y


6.6      Organisation pratique des fichiers
on aura en général :
 un fichier entête .h pour chaque définition de classe
 un fichier source .cpp pour la définition des fonctions publiques de chaque classe.
 Les fichiers d'application .cpp qui utilisent les classes.
 un projet contenant les fichiers d'application .cpp et les fichiers .cpp des classes.
#ifndef RECTANGLE_H                                    // fichier rectangle.h :
#define RECTANGLE_H
class Rectangle
{
     int x0, y0, x1, y1 ;                    // membres privés
     unsigned c; // couleur
     void modifie(int x0, int y0, int x1, int y1 );
public :
     Rectangle( int x0, int y0, int x1, int y1, unsigned col = NOIR );
     unsigned hauteur( ) { return x1 - x0 ; }
     unsigned largeur ( ) { return y1 - y0 ; }
     unsigned couleur ( ) { return c ; }
     void dessine ( ) ;
     void aggrandit( int dx, int dy )        ;
     void aggrandit( float taux )            ;
};
#endif
#include "rectangle.h"                               // fichier rectangle.cpp (extrait)
void Rectangle::dessine( )
{   ...
}
void Rectangle :: aggrandit( int dx, int dy )
{   ...
    modifie( .... ) ;
}

#include "rectangle.h"               // fichier appli.cpp
int main()
{
     Rectangle r( 10, 50, 20, 150 );
     unsigned hauteur, largeur, couleur;

      longueur = r. largeur();
      r.aggrandit( 2, 5 );
}

le projet contient les fichiers applic.cpp et rectangle.cpp

6.7      exercice :
réaliser une classe Point permettant de manipuler un point du plan.
 Les coordonnées du point seront privées.
 le constructeur recevra en argument les coordonnées du point (float)
 une fonction membre déplace() permettra d'effectuer une translation du point.
 Une fonction membre affiche() affichera les coordonnées du point.
Ecrire un programme d'essai qui déclare un point, l'affiche, le déplace et l'affiche à nouveau.
Compléter la classe pour que la fonction affiche indique aussi le nombre d'objets de type point.
                                 7. Construction des objets


7.1      Classe de mémorisation des objets.
Différentes classes de mémorisation des objets :
Objets automatiques (locaux): déclarés localement dans un bloc et recréés à chaque appel de la fonction
Objets statiques (globaux) : déclarés en dehors de toute fonction : créés avant main(), détruits après.
Objets dynamiques : créés par new et supprimés par delete.
Objets temporaires (ils sont sans nom): créés pour mémoriser un résultat intermédiaire dans le calcul d’une
expression, passage de paramètres par valeur, retour de fonction par valeur.

Point p1( 2, 2 );          // objet statique

void f ( Point p )
{
    ...
    Point p2( 0, 0 );   // objet automatique, constructeur de p2 appelé ici
    ...
    point *ptr     ;            // pas d'appel de constructeur ici
    ...
    ptr = new Point( 1, 1); // objet dynamique, constructeur appelé ici
    ...
    delete ptr;                 // destructeur de l’objet dynamique appelé ici
    ...
}                               // destructeur de p2 appelé ici

               // le point p1 est construit avant d’entrer dans main()
int main ()
{
    ...
    f ( Point( 3, 3 ) ); // création d’un objet temporaire
                                  // destruction de l’objet temporaire (au plus tôt)
    ...
}
               // destruction du point p1



7.2      Constructeur par défaut.
 S’il n’y a pas de constructeur, le compilateur génère un constructeur par défaut sans paramètre.
 Le constructeur par défaut, sans paramètre, permet de créer des objets non initialisés.
 De façon générale un constructeur par défaut est un constructeur qui peut être appelé sans paramètre.
  (Soit il n'existe aucun paramètre, soit tous les paramètres ont des valeurs par défaut).
 Si un ou plusieurs constructeurs sont définis par la classe, le constructeur pas défaut n’est pas généré.

class Texte1
{
    int taille;
    char *ptr;
public :
    ...               // un constructeur par défaut est généré
};
Texte1 t;       // ok

class Texte2
{
    int taille;
    char *ptr;
public :
    Texte2 ( char * ); // pas de constructeur par défaut généré
};
Texte2 t;                // illégal
Texte2 t ( " je suis le contenu du texte " );

class Texte3
{
    int taille;
    char *ptr;
public :
    Texte3 ()
          { taille = 80; ptr = new char[ taille + 1 ] ; } // constructeur par défaut
    Texte3 ( char * );
};
7.3      Constructeur de recopie.

7.3.1    Problème à résoudre
Class Tableau
{
    int *ptr;
    int nb; // taille du tableau
public :
    Tableau ( int n ) { ptr = new int[ nb = n ]; }
    ~Tableau () { delete [] ptr ; }
    ...
};

int main()
{
     Tableau t1( 3 );
     Tableau t2 ( t1 ) ;
          ...
     return 0;
}

                                                                          t1
Le tableau t2 est créé à partir du tableau t1. Le compilateur fait
une copie automatique de tous les champs de t1 dans t2. Les                 3
champs sont recopiés mais pas les zones pointées.


                                                                          t2

On constate que le tableau d'entiers alloué en mémoire est                  3
référencé par deux objets différents.
A la destruction des objets t1 et t2, cette zone allouée unique est libérée deux fois par le destructeur de t1 et
t2, ce qui provoque une erreur à l'exécution.

                                                                     t1
Il faudrait obtenir :
les deux tableaux t1 et t2 sont indépendants, la zone
allouée pointée pour t2 est une copie de la zone allouée
                                                                      3
pour t1.

Il faut créer un constructeur de recopie.                                                           copie
                                                                     t2

                                                                      3


7.3.2    définition.
Son prototype est de la forme :
                             Classe( Classe & ) ou mieux         Classe( const Classe & )

sert à créer des clones, c’est à dire à dupliquer les objets.


class Complex
{
    int x, y ;
public :
    Complex( int x, int y ) ;                 // constructeur 'normal'
    Complex ( const Complex &z )              // constructeur de recopie (inutile ici)
               { x = z.x; y = z.y; }
};

7.3.3    Utilisations :
Appel lors de l’initialisation d’un objet par un autre objet de la classe

Complex z1( 2, 4 );

Complex z2( z1 );                    // appel du constructeur de recopie
Complex z3 = z1 ;                    // appel du constructeur de recopie

Appel lors du passage d’objet en paramètres par valeur à une fonction pour recopier le paramètre effectif
dans le paramètre formel.

int module( Complex z );             // prototype de fonction (pas une fonction membre)

Complex z( 1, 2 );
int m = module( z ); // appel du constructeur de recopie
                   // pour le passage de paramètre par valeur

Appel lors du renvoi d’un objet par une fonction pour recopier la valeur de retour dans un objet temporaire :

Complex racine( ... );               // prototype de fonction(pas une fonction membre)

Complex z = racine( ...);       // appel du constructeur de recopie
                       // pour le retour de la fonction


Class Tableau
{
    int *ptr;
    int nb; // nombres d’éléments
public :
    Tableau (int n) { ptr = new int[ nb = n ]; }
    Tableau ( const Tableau &t );
    ~Tableau () { delete [] ptr ; }
    ...
};

Tableau :: Tableau ( const Tableau &t )
{
    nb = t.nb;
    ptr = new int [ nb ] ;
    memcpy( ptr, t.ptr, nb*sizeof( int ) ) ;
}

Tableau t1;
Tableau t2 ( t1 ) ;

Point Point :: symetrique()
{
    Point p ; // création d'un point automatique (local)
    p.x = -x; p.y = -y ;
    return p; // recopie dans un point temporaire
                    //  appel constructeur de recopie
}
Point &Point :: symetrique()
{
    Point p ; // création d'un point automatique (local)
    p.x = -x; p.y = -y ;
    return p; // erreur à la compilation : référence sur un objet temporaire
}

Point *Point :: symetrique()
{
    Point p ; // création d'un point automatique (local)
    p.x = -x; p.y = -y ;
    return &p;      // pas d'erreur déclarée !!!!
}
// faire Point *p = new Point ; ... return p ; est aussi une mauvaise solution

Point p1( 2, 5 ), p2 = p1.symetrique() ;

7.4      Cas des objets avec des objets membres.
Dans un constructeur, il y a d'abord construction des membres (donc appel des constructeur par défaut des
objets membres) puis exécution des instructions du bloc du constructeur.

Les objets membres sont donc d'abord construit avant l’objet englobant (et récursivement). Donc :
 Si les objets membres disposent d’un constructeur par défaut, celui-ci est appelé avant que le constructeur
   de l’objet englobant soit lui-même appelé.
 Si les objets membres ne disposent pas d’un constructeur par défaut, il faut faire un appel explicite au
   constructeur souhaité.
 L'appel des constructeurs a lieu en dehors du bloc du constructeur.
 Même raisonnement avec tous les constructeurs ( constructeur de recopie compris ).

class Point;
class Segment
{                                                                             Exécuté avant les
        Point a, b;
public :
                                                                              instructions du
        Segment( int, int, int, int );                                        constructeur
        ...
}
Segment :: Segment( int x1, int y1, int x2, int y2 ) : a( x1, y1 ), b( x2, y2 )
{ .....
}

7.5      initialisation des objets ( <> affectation ).
L'initialisation d'un objet est toujours faite par un constructeur.

Il y a initialisation d’un objet dans les 3 cas suivants:
1 - Déclarations d’un objet avec intialisation : appel d'un constructeur.

Point a = 5 ; // ou a( 5 ) il doit exister un constructeur à un argument entier
Point b = a ; // ou b( a ) il doit exister un constructeur à un argument Point

2 - Transmission d’un objet par valeur, en argument d’un appel d’une fonction : appel d'un constructeur de
recopie.

3 - Transmission d’un objet par valeur, en valeur de retour d’une fonction : appel d'un constructeur de
recopie.


7.6      Affectation d’objets.
L’opérateur d’affectation est le signe =.
Il recopie tous les membres de l’objet source dans ceux de l’objet destination.
Il faudra définir un opérateur d’affectation personnalisé dès que l’objet contient des pointeurs vers une zone
dynamique.

Cas des objets membres : L’opérateur d’affectation par défaut utilise l’opérateur d’affectation pour chacun
des objets membres.

Cas des pointeurs membres : Les membres de type pointeur sont copiés, mais pas les zones pointées.



7.7      Tableaux d’objets.

Il est possible de construire un tableau d’objets d’une classe donnée, à condition que la classe possède un
constructeur par défaut (ou de les initialiser explicitement). Les éléments du tableau sont alors initialisés avec
ce constructeur.
class Point
{ ....
public :
       Point ( int, int );
}
Point tab[ 10 ] ; // illégal

class Point
{ ....
public :
       Point ( int, int = 0 );
}
Point tab[ 5 ] = { Point( 1, 2), 3, Point( 4 ), 9, 6 } ;
       // crée le tableau { ( 1, 2), ( 3, 0), ( 4, 0 ), ( 9, 0) ( 6, 0 ) }
       // mais il est impossible d'initialiser un tableau dynamique
                                              8. s amis.


8.1     Fonction amie.

Une fonction amie d’une classe A est une fonction, n’appartenant pas à la classe A, autorisée à accéder aux
membres non publiques de la classe A.
Le concepteur de la classe doit déclarer dans la classe la fonction amie avec le mot clé friend.

class Point
{
    int x, y;
public :
    friend void affiche( const Point &p );
    Point( int abs = 0 ; ord = 0 ) { x = abs; y = ord ; }
    ...
};

void affiche ( const Point &p )
{
    cout << " abscisse = " << p.x << " ordonnée = " << p.y ;
}

Une fonction amie d’une classe A peut appartenir à une autre classe B.

class Fenetre ;
class Point
{
    int x, y;
public :
    friend void Fenetre :: affiche( const Point &p );
    Point( int abs = 0 ; ord = 0 ) { x = abs; y = ord ; }
    ...
};

8.2     Classe amie.
Une classe B est amie d’une classe A. Toutes les fonctions membres de la classe B sont amies de A.
classe Fenetre ;
class Point
{    ...
     friend class Fenetre ; ... } ;
Les fonctions amies sont une infraction à l'encapsulation

				
DOCUMENT INFO
Shared By:
Categories:
Tags:
Stats:
views:7
posted:5/2/2012
language:Latin
pages:22
Description: C