E-gradiva > Računalništvo > Programiranje > Načrtovanje in razvoj programskih aplikacij > Objektno programiranje > Polimorfizem

Prijava

Polimorfizem

 

 

Dedovanje in polimorfizem sta dve najpomembnejši lastnosti objektnega programiranja. Prvo smo že spoznali, druga pa označuje princip, da lahko različni objekti razumejo isto sporočilo in se  nanj odzovejo vsak na svoj način. Obe lastnosti sta osnova objektnega programiranja in omogočata hitrejši razvoj  in lažje vzdrževanje programske kode.

 

 

Primer:

 

Imejmo poleg razreda  student,  iz razreda  oseba izpeljana še razreda profesor in asistent. Oba naj imata po en dodaten element: profesor naj ima predmet, ki ga poučuje, asistent pa predmet, pri katerem ima vaje.  Vsak od njiju ima svojo inačico metode izpiši, ki izpiše podatke tega objekta.

 

 

Oglejmo si primer, ko želimo vnašati in izpisovati več objektov tipa študent, asistent ali profesor. Za shranjevanje bomo uporabili polje kazalcev. Ker ne vemo kakšne elemente bomo gradili (ta podatek bo znan šele v izvajanju), bomo shranjevali kazalce na skupni nadrazred.

 

  1. #include  "student.h"
    #include "asistent.h"
    #include "profesor.h"
    #include <iostream.h>

    const
    int max_oseb = 4;


    int
    main()
    {

    oseba* ptr_polje_oseb[max_oseb]; //polje za shranjevanje oseb
    oseba* ptr_začasna;


    cout << "Vnesi " << max_oseb << " osebe !" << endl;

    char
    tip_osebe[];

    char
    ime[vel_ime];
    char
    naslov[vel_naslov];
    char
    smer[vel_smer];

    char
    vaje[vel_vaje];

    char
    predmet[vel_predmet];


    for
    (int i = 0; i < max_oseb; i++)
    {


    cout << endl << endl << "Vnesi tip osebe (S, A, P): ";
    cin >> tip_osebe;

    cout << "Vnesi ime : ";
    cin << ime;
    cout << "Vnesi naslov : ";

    cin >> naslov;

    if
    (tip_osebe == 'S')
    {


    cout << "Smer studenta : ";
    cin >> smer;
    ptr_zacasna = new student (ime, naslov, smer);
    }


    else if
    (tip_osebe == 'A')
    {

    cout << "Predmet asistenta : ";

    cin >> vaje;
    ptr_zacasna = new asistent (ime, naslov, vaje);
    }


    else if
    (tip_osebe == 'P')
    {

    cout << "Predmet profesorja : ";

    cin >> vaje;
    ptr_zacasna = new profesor (ime, naslov, predmet);
    }


    else

    {

    cout << "Napacen tip osebe!" << endl;
    cout << "Ustvarilo bom objekt razreda oseba!";

    ptr_zacasna = new oseba (ime, naslov);
    }

    ptr_polje_oseb[i] = ptr_zacasna;
    }


    //izpis vnesenih oseb
    for (i = 0; i < max_oseb; i++)
    {


    ptr_polje_oseb[i] ->izpisi();
    cout << endl;
    }



    //brisanje polja kazalcev

    for (i = 0; i < max_oseb; i++)

    delete
    ptr_polje_oseb[i];

    return
    0;
    }


 

 

 

Razložimo program! Najprej v zanki preberemo tip osebe ter ime in naslov osebe. Glede na tip osebe preberemo še smer, vaje ali predmet in ustvarimo  objekt ustreznega razreda s pomočjo operatorja new. Ta nam vrne kazalec na objekt (student* ali asistent* oz. profesor*). Ta kazalec shranimo v spremenljivko ptr_zacasna, ki pa je tipa oseba*. Kako lahko to storimo?  To je mogoče zato, ker je vsak študent (oz. asistent ali profesor) tudi oseba, zato lahko napravimo pretvorbo kazalca: npr. student*  v oseba*. Pretvorba se napravi implicitno pri operatorju new. Pretvorbo bi lahko zahtevali tudi eksplicitno z naslednjim zapisom:

 

ptr_zacasna = (oseba*)new student(ime, naslov, smer);

 

 

Kadar kot tip osebe vnesemo nepravilno vrednost, ustvarimo objekt tipa oseba. Ko smo vnesli vse osebe,  jih še izpišemo in nato zbrišemo (sproščanje dinamično dodeljenega pomnilnika!)

 

Prikaz delovanja programa:

 

Vnesi 4 osebe!

 

Vnesi tip osebe (S, A, P):   S

Vnesi ime:  Janez

Vnesi naslov:  Mladinska

Smer studenta   :  Anglescina

 

Vnesi tip osebe (S, A, P):   A

Vnesi ime:  Metka

Vnesi naslov:  Slovenska

Predmet asistenta:  Nemscina

 

Vnesi tip osebe (S, A, P):   P

Vnesi ime:  France

Vnesi naslov:  Ljubljanska

Predmet profesorja:  Računalnistvo

 

Vnesi tip osebe (S, A, P):   k

Vnesi ime:  Marija

Vnesi naslov:  Betnavska

Napacen tip osebe!

Ustvaril bom objekt razreda oseba!

 

 

Ime osebe:  Janez

Naslov:  Mladinska

 

Ime osebe:  Metka

Naslov:  Slovenska

 

Ime osebe:  France

Naslov: Ljubljanska

 

Ime osebe:  Marija

Naslov:  Betnavska

 

 

 

Polimorfna redefinicija

 

 

Če si ogledamo izpis programa opazimo, da so se za vsak vnešeni objekt izpisali samo podatki, ki so zapisani v razredu oseba in ne vsi podatki študenta, asistenta in profesorja. Zakaj?

 

Ko smo objekte shranjevali, smo kazalec pretvorili v tip oseba*. Ko kličemo metodo izpisi, zato kličemo metodo oseba::izpisi. Vidimo, da navadna redefinicija metode v tem primeru ne zadošča. Čeprav imamo samo kazalce na razred oseba, želimo, da vsak objekt ohrani sebi lastno obnašanje ob klicu metode izpisi.  Uporabiti moramo polimorfno redefinicijo.

 

Polimorfno redefinicijo omogočimo z definicijo virtualne metode. Metodo izpisi moramo v razredu oseba definirati kot virtualno, kar storimo na naslednji način:

 

virtual void izpisi() const;

 

Ta definicija pove, da naj izpeljani objekt kliče svojo funkcijo izpisi, čeprav bi bil klic izvršen preko kazalca na nadrazred (oseba*). Ob takšni definiciji metode izpisi v razredu oseba, bo prejšnji primer izpisal naslednje:

 

 

Vnesi 4 osebe!

 

Vnesi tip osebe (S, A, P):   S

Vnesi ime:  Janez

Vnesi naslov:  Mladinska

Smer studenta:  Anglescina

 

Vnesi tip osebe (S, A, P):   A

Vnesi ime:  Metka

Vnesi naslov:  Slovenska

Predmet asistenta:  Nemscina

 

Vnesi tip osebe (S, A, P):   P

Vnesi ime:  France

Vnesi naslov:  Ljubljanska

Predmet profesorja:  Računalnistvo

 

Vnesi tip osebe (S, A, P):   k

Vnesi ime:  Marija

Vnesi naslov:  Betnavska

Napacen tip osebe!

Ustvaril bom objekt razreda oseba!

 

Ime osebe:  Janez

Naslov:  Mladinska

Smer:  Angleščina

 

Ime osebe:  Metka

Naslov:  Slovenska

Vaje pri:  Nemščina

 

Ime osebe:  France

Naslov:  Ljubljanska

Predmet:  Računalništvo

 

Ime osebe:  Marija

Naslov:  Betnavska

 

 

 

 

Problem se pojavi tudi pri brisanju dinamično alociranih objektov. Pri klicu operatorja delete se bo  klical destruktor za razred oseba namesto destruktor ustreznega objekta. Zato moramo tudi destruktor definirati kot virtualno metodo:

 

virtual ~oseba();