IFT1166 --- Automne 99 --- 17/10/1999 --- Demo 9
 

                          IFT 1166 --- DEMO #9


Contenu

préparation au TP3

Utilisation du patron de classe défini en demo #7

Héritage simple, public Typage statique / typage dynamique

Exercice

a) Définissez une classe <Partition> en utlisant le patron de classe <List> de la démonstration 7. Vous vous appuierez sur le fait qu' une partition peut être vue comme une liste de notes, une note étant par exemple donnée par une fréquence (en Hz) et une durée (en ms).
 
Il est vous est donné libre choix de définir d'autres classes (par exemple une classe note) pour y parvenir. Le but de la classe Partition étant simplement de fournir une interface simple permettant au moins d'ajouter une note, et d'afficher les notes rentrées.
 

b) Soit une classe de base <Instrument>
 

class Instrument {

    int tessiture; // nombre d'octaves que l'on peut produire avec l'instrument
    int tonalite;  // tonalite de l'instrument (Hz)
    string nom;  // nom de l'instrument

public:

    Instrument(string n, int t=0, int ton=0) {
        cout << "   constructeur Instrument\n";
        nom = n;
        tessiture = t;
        tonalite = ton;
    }

    Instrument(const Instrument & I); // pas vraiment necessaire ici, mais illustratif
    Instrument & Instrument::operator= (const Instrument & I); // pas vraiment necessaire ici, mais illustratif

    void jouer(Partition &p) {
        cout << "   Instrument:" << nom << " => ";
        p.affiche();
    }

    void info() {
        cout << "   info Instrument " << nom << " tessiture " << tessiture << " tonalite " << tonalite << endl;
    }
};

Et deux classes dérivées <Cuivre> et <Corde> héritées de la classe <Instrument> (respectivement la classe des cuivres et la classe des instruments à cordes) et dont le squelette peut ressembler à:
 
class Cuivre : public Instrument{
    int justePourVoir;
public:

    Cuivre (string nom);

    void jouer(Partition & p) { // redifinition d'une fct membre
        cout << "   Section Cuivre , jouer:\n";
        Instrument::jouer(p);
    }

    void infoCuivre() { // une fct specifique a la classe Cuivre
        cout << "   info Cuivre : justePourVoir=>" << justePourVoir << endl;
    }
};
// ---------------------------------------------------------------
class Corde : public Instrument {
public:
    Corde(string nom, int tess=0, int ton = 0); // constructeur
    Corde (const Corde & C); // constructeur de recopie

    Corde & Corde::operator= (const Corde & C); // operateur d'affectation
};

Complétez/modifez ces classes de manière à pouvoir compiler et exécuter correctement un programme principal utilisant des objets de ces classes.

c) Reprendre au besoin votre code de manière à pouvoir exécuter le programme principal qui suit. Notez que ce programme contient des erreurs de conception liées à l'héritage, qu'il convient d'identifier dans un premier temps.

// exemple de programme montrant tous les aspects de l'héritage simple public il contient des erreurs de conception à identifier

int main() {

    // creation d'une "partition" de nom "random" avec un nombre de 10 notes aleatoires
    Partition p("random");
    for (int i=0; i<10; i++) p.ajoute(440+(int) (200.0*rand()/(RAND_MAX+1.0)));
    p.affiche(); // affichage de cette partition

    // creation d'objets et de ptrs divers pour illustrer l'heritage simple
    Instrument I("Inst"),I2("Inst2"),I3("inst3",10,220),*pi;
    Cuivre Cu1("Cuivre1"),Cu2("Cuivre2"),*pcu=&Cu1;
    Corde Co1("Corde1"),Co2("Corde2",6,440);

    // essais
    I.jouer(p);
    Cu1.jouer(p);
    Co1.jouer(p);
    cout << Cu1.tessiture;
 
    // les conversions entre objets
    cout << "conversion entre objets\n";
    I = Cu1;
    I.jouer(p); // le jouer de la classe Instrument
    I.infoCuivre();

    Cu1 = I;

    // les conversions entre pointeurs dans le sens *base = *derivee
    cout << "convertion entre ptrs\n";
    pi = pcu;
    pi->jouer(p);

    // les conversions entre pointeurs dans le sens *derivee = *base
    pcu = pi;
    pi = &I2;
    pi->info();
    pcu = (Cuivre *) pi;
    pcu->jouer(p);
    pcu->info();
    pcu->infoCuivre();   // ouatch !!!

    // que se passe t-il avec les constructeurs de recopie ?
    cout << "Testons maintenant la recopie\n";
    Cuivre Cu3 = Cu2;
    Cu3.info();
    Corde Co3 = Co2;
    Co3.info();
 

    // que se passe t-il avec les operateurs d'affectation ?
    cout << "Testons maintenant l'affectation\n";
    I3.info();
    I = I3;
    I.info();
    Cu1 = Cu2;
    Cu1.info();
    Co2.info();
    Co1 = Co2;
    Co1.info();

 
    return 0;
}
 

d) Identifiez systématiquement les fonctions, les constructeurs et les opérateurs utilisés par ce programme.

e) Modifiez votre code de manière à gérer le typage dynamique lors d'appels à des fonctions définies dans la classe de base et dans une classe dérivée.
 

PS: vous pouvez remplacer <Instrument> (resp. <Cuivre> et <Cordre>) par toute autre classe de base (resp dérivées) de votre choix.