Objektno programiranje - nadaljevanje - · PDF fileKlic metod in dostop do podatkov objektov,...
Transcript of Objektno programiranje - nadaljevanje - · PDF fileKlic metod in dostop do podatkov objektov,...
Objektno programiranje Objektno programiranje - nadaljevanje- nadaljevanje
Milan Ojsteršek Milan Ojsteršek
Center za heterogeno Center za heterogeno procesiranjeprocesiranje
Primer uporabe Primer uporabe destruktorja:destruktorja:
int int main()main()
{{
Kompleksno* x;Kompleksno* x;
x = x = newnew Kompleksno(1.0,1.0); // klic konstruktorja Kompleksno(1.0,1.0); // klic konstruktorja za ustvarjanjeza ustvarjanje
//dinamičnega objekta//dinamičnega objekta
cout << "x: ";cout << "x: ";
x->izpisi();x->izpisi();
delete x; delete x; // klic destruktorja // klic destruktorja
return return 0;0;
Klic metod in dostop do Klic metod in dostop do podatkov objektov, ki so podatkov objektov, ki so dinamično generiranidinamično generirani
Za dostop do metod ali podatkov v Za dostop do metod ali podatkov v objektih, ki so dinamično generirani objektih, ki so dinamično generirani (generirani so z uporabo kazalcev) (generirani so z uporabo kazalcev) uporabljamo operator ->.uporabljamo operator ->.
V našem primeru smo uporabili ta V našem primeru smo uporabili ta
operator v operator v x ->izpisi().x ->izpisi(). Enakovreden Enakovreden zapis je tudi: zapis je tudi: (*x).izpisi()(*x).izpisi();;
Konstantni objektiKonstantni objekti
To so objekti, ki jim ne moremo To so objekti, ki jim ne moremo spremeniti vrednosti podatkov. spremeniti vrednosti podatkov.
Primer:Primer:
const const Kompleksno i(0.0,1.0); Kompleksno i(0.0,1.0);
Konstantne metodeKonstantne metode
V konstantnem objektu lahko kličemo V konstantnem objektu lahko kličemo samo konstantne metode, to so tiste samo konstantne metode, to so tiste metode, ki ne spremenijo podatkov v metode, ki ne spremenijo podatkov v objektu. Primer takšne metode je objektu. Primer takšne metode je metoda izpisi:metoda izpisi:
void void Kompleksno::izpisi() constKompleksno::izpisi() const
{ cout << '(' << realni << ", " { cout << '(' << realni << ", " << imaginarni << ')';<< imaginarni << ')';
Konstantni podatkiKonstantni podatki Poleg konstantnih metod lahko definiramo v razredu tudi konstantne Poleg konstantnih metod lahko definiramo v razredu tudi konstantne
podatke.podatke.Primer:Primer: class class Kompleksno {Kompleksno {public:public:
Kompleksno(); Kompleksno(); // privzeti // privzeti konstruktorkonstruktorKompleksno(double, double); Kompleksno(double, double); // konstruktor// konstruktor
private:private:double realni; // realni deldouble realni; // realni deldouble imaginarni; // imaginarni deldouble imaginarni; // imaginarni del
constconst double pi; double pi;};}; Konstruktor kličemo na naslednji način:Konstruktor kličemo na naslednji način:Kompleksno::Kompleksno(double r=0.0, double i=0.0) Kompleksno::Kompleksno(double r=0.0, double i=0.0) : realni(r), imaginarni(i), pi(3.14): realni(r), imaginarni(i), pi(3.14){{}}
Kazalec thisKazalec this
Pri vsakem klicu metode se vanjo kot argument prenese še Pri vsakem klicu metode se vanjo kot argument prenese še naslov objekta nad katerim ta metoda deluje. Naslov objekta, naslov objekta nad katerim ta metoda deluje. Naslov objekta, ki je klical metodo lahko uporablja tudi programer.ki je klical metodo lahko uporablja tudi programer.
Primer:Primer: classclass Preizkus { Preizkus {publicpublic::
Preizkus(Preizkus(intint = 0); // privzet konstruktor = 0); // privzet konstruktorvoidvoid izpisi() izpisi() constconst;;
privateprivate::intint x; x;
};};
Kazalec thisKazalec thisPreizkus::Preizkus(Preizkus::Preizkus(intint a) { x = a; } // konstruktor a) { x = a; } // konstruktor voidvoid Preizkus::izpisi() Preizkus::izpisi() constconst{{
cout << " x = " << x << endlcout << " x = " << x << endl << " << " thisthis->x = " << ->x = " << thisthis->x << endl->x << endl << "(*<< "(*thisthis).x = " << (*).x = " << (*thisthis).x << endl;).x << endl;
}}main()main(){{
Preizkus a(12);Preizkus a(12); a.izpisi();a.izpisi(); returnreturn 0; 0;}} Program izpiše:Program izpiše: x = 12x = 12 this->x = 12this->x = 12(*this).x = 12(*this).x = 12
Prekrivanje operatorjev Prekrivanje operatorjev (operator overloading)(operator overloading)
Določene operatorje Določene operatorje žželimo elimo prekriti. Npr. operacije + prekriti. Npr. operacije + nimamo definirane za nimamo definirane za kompleksna števila.kompleksna števila.
Prekrivanje operatorjevPrekrivanje operatorjevclassclass Kompleksno { Kompleksno {publicpublic::
Kompleksno(Kompleksno(doubledouble = 0.0, = 0.0, doubledouble = 0.0); = 0.0); // prekrivanje operatorja za setevanje// prekrivanje operatorja za setevanje
Kompleksno Kompleksno operatoroperator+(+(constconst Kompleksno &) Kompleksno &) constconst; ; // prekrivanje operatorja za odstevanje // prekrivanje operatorja za odstevanje
Kompleksno Kompleksno operatoroperator-(-(constconst Kompleksno &) Kompleksno &) constconst; ; // prekrivanje operatorja za prirejanje// prekrivanje operatorja za prirejanje Kompleksno &Kompleksno &operatoroperator=(=(constconst Kompleksno &); Kompleksno &); voidvoid izpisi() izpisi() constconst; ; privateprivate::
doubledouble realni; // realni del realni; // realni deldoubledouble imaginarni; // imaginarni del imaginarni; // imaginarni del
};};
Prekrivanje operatorjevPrekrivanje operatorjev// konstruktor// konstruktorKompleksno::Kompleksno(Kompleksno::Kompleksno(doubledouble r, r, doubledouble i) i){{
realni = r;realni = r;imaginarni = i;imaginarni = i;
}}// Prekrivni operator sestevanja// Prekrivni operator sestevanjaKompleksno Kompleksno::Kompleksno Kompleksno::operatoroperator+(+(constconst Kompleksno Kompleksno
&operand2) &operand2) constconst{{
Kompleksno vsota;Kompleksno vsota;vsota.realni = realni + operand2.realni;vsota.realni = realni + operand2.realni;vsota.imaginarni = vsota.imaginarni = imaginarni + imaginarni +
operand2.imaginarni;operand2.imaginarni;returnreturn vsota; vsota;
}}
Prekrivanje operatorjevPrekrivanje operatorjev// Prekrivni operator odstevanja// Prekrivni operator odstevanjaKompleksno Kompleksno::Kompleksno Kompleksno::operatoroperator-(-(constconst Kompleksno &operand2) Kompleksno &operand2)
constconst{{
Kompleksno razlika;Kompleksno razlika;razlika.realni = realni - operand2.realni;razlika.realni = realni - operand2.realni;razlika.imaginarni = imaginarni – razlika.imaginarni = imaginarni –
operand2.imaginarni;operand2.imaginarni;returnreturn razlika; razlika;
}} // Prekrivni operator =// Prekrivni operator =Kompleksno& Kompleksno::Kompleksno& Kompleksno::operatoroperator=(=(constconst Kompleksno &desno) Kompleksno &desno){{
realni = desno.realni;realni = desno.realni;imaginarni = desno.imaginarni;imaginarni = desno.imaginarni;returnreturn * *thisthis; // omogoca veckratno prirejanje; // omogoca veckratno prirejanje
}}
Prekrivanje operatorjevPrekrivanje operatorjev
// Prikazi objekt Kompleksno v // Prikazi objekt Kompleksno v obliki: (a, b)obliki: (a, b)
voidvoid Kompleksno::izpisi() Kompleksno::izpisi() constconst
{ cout << '(' << realni << ", " { cout << '(' << realni << ", "
<< imaginarni << ')';<< imaginarni << ')';
}}
Prekrivanje operatorjev – Prekrivanje operatorjev – glavna funkcijaglavna funkcija
main()main(){{
Kompleksno x, y(4.3, 8.2), z(3.3, 1.1);Kompleksno x, y(4.3, 8.2), z(3.3, 1.1);cout << "x: ";cout << "x: ";x.izpisi();x.izpisi();cout << endl << "y: ";cout << endl << "y: ";y.izpisi();y.izpisi();cout << endl << "z: ";cout << endl << "z: ";z.izpisi();z.izpisi();x = y + z;x = y + z;cout << endl << endl << "x = y + z:" << endl;cout << endl << endl << "x = y + z:" << endl;x.izpisi();x.izpisi();cout << " = ";cout << " = ";y.izpisi();y.izpisi();cout << " + ";cout << " + ";z.izpisi();z.izpisi();
Prekrivanje operatorjev – Prekrivanje operatorjev – glavna funkcija - glavna funkcija - nadaljevanjenadaljevanje
x = y - z;x = y - z;
cout << endl << endl << "x = y - z:" << endl;cout << endl << endl << "x = y - z:" << endl;
x.izpisi();x.izpisi();
cout << " = ";cout << " = ";
y.izpisi();y.izpisi();
cout << " - ";cout << " - ";
z.izpisi();z.izpisi();
cout << endl;cout << endl;
returnreturn 0; 0;
}}
Program izpiše:Program izpiše:
x: (0, 0)x: (0, 0)y: (4.3, 8.2)y: (4.3, 8.2)z: (3.3, 1.1)z: (3.3, 1.1) x = y + z:x = y + z:(7.6, 9.3) = (4.3, 8.2) + (3.3, (7.6, 9.3) = (4.3, 8.2) + (3.3, 1.1)1.1)
x = y - z:x = y - z:(1, 7.1) = (4.3, 8.2) - (3.3, 1.1)(1, 7.1) = (4.3, 8.2) - (3.3, 1.1)
Vmesnik razredaVmesnik razreda
Vmesnik razreda predstavljajo Vmesnik razreda predstavljajo vsi javni elementi razreda. vsi javni elementi razreda. Uporabnik nekega razreda Uporabnik nekega razreda mora poznati le njegov mora poznati le njegov vmesnik, podrobnosti o vmesnik, podrobnosti o implementaciji pa zanj niso implementaciji pa zanj niso pomembne. Tako je pomembne. Tako je programska koda neodvisna od programska koda neodvisna od implementacije.implementacije.
Prijateljske funkcijePrijateljske funkcije
Do privatnih metod ali podatkov Do privatnih metod ali podatkov razreda lahko dostopajo samo razreda lahko dostopajo samo prijateteljske funkcije razreda prijateteljske funkcije razreda (friend funkcije), čeprav niso člani (friend funkcije), čeprav niso člani razreda.razreda.
Primer – prijateljske Primer – prijateljske funkcijefunkcije
classclass Stevec { Stevec {friendfriend voidvoid doloci_x(Stevec &, doloci_x(Stevec &, intint););
// opredelitev friend funkcije// opredelitev friend funkcijepublicpublic::
Stevec() { x = 0; } // konstruktorStevec() { x = 0; } // konstruktorvoidvoid izpisi() const { cout << x << endl; } izpisi() const { cout << x << endl; }
// izhod// izhodprivateprivate::
intint x; // podatkovni element razreda x; // podatkovni element razreda};}; voidvoid doloci_x(Stevec &c, doloci_x(Stevec &c, intint vred) vred){{
c.x = vred; // dovoljeno: doloci_x je friendc.x = vred; // dovoljeno: doloci_x je friend// funkcija Stevca// funkcija Stevca}}
Primer – prijateljske Primer – prijateljske funkcije – glavna funkcijafunkcije – glavna funkcija
main()main(){{
Stevec objekt;Stevec objekt;
cout << "objekt.x po uvedbi: ";cout << "objekt.x po uvedbi: ";objekt.izpisi();objekt.izpisi();cout << "objekt.x po klicu friend funkcije cout << "objekt.x po klicu friend funkcije
doloci_x: ";doloci_x: ";doloci_x(objekt, 8); // dolocitev x s friendoloci_x(objekt, 8); // dolocitev x s friend d funkcijofunkcijoobjekt.izpisi();objekt.izpisi();
returnreturn 0; 0;
}} Program izpiše:Program izpiše: objekt.x po uvedbi: 0objekt.x po uvedbi: 0objekt.x po klicu friend funkcije doloci_x: 8objekt.x po klicu friend funkcije doloci_x: 8
DEDOVANJE DEDOVANJE
Z uporabo Z uporabo dedovanjadedovanja iz obstoječih iz obstoječih razredov tvorimo nove razrede.razredov tvorimo nove razrede.
Takšno tvorjenje razredov imenujemo Takšno tvorjenje razredov imenujemo izpeljavaizpeljava in razrede, ki tako in razrede, ki tako nastanejo nastanejo izpeljaniizpeljani razredirazredi ali ali podrazredipodrazredi. . Izpeljani razred ima torejIzpeljani razred ima torej svoj svoj nadrazrednadrazred, tj. razred, iz katerega je , tj. razred, iz katerega je izpeljan. Dedovanje je lahko izpeljan. Dedovanje je lahko enkratnoenkratno ali ali večkratnovečkratno – v tem primeru je razred – v tem primeru je razred izpeljan iz dveh aliizpeljan iz dveh ali več nadrazredov.več nadrazredov.
DEDOVANJEDEDOVANJE
Izpeljani razred Izpeljani razred podedujepodeduje vse elemente vse elemente svojega nadrazreda. K tem elementom pa svojega nadrazreda. K tem elementom pa lahko doda še svoje elemente (podatke in lahko doda še svoje elemente (podatke in metode) inponovno definira metode iz svojega metode) inponovno definira metode iz svojega nadrazreda. Zato lahko izpeljanenadrazreda. Zato lahko izpeljane razrede razrede razumemo kot posebne primere svojih razumemo kot posebne primere svojih nadrazredov. Takonadrazredov. Tako izpeljani razredi izpeljani razredi predstavljajo predstavljajo specializacijospecializacijo, nadrazredi pa , nadrazredi pa posplošitevposplošitev..
Ker izpeljanKer izpeljanii razred podeduje vse elemente razred podeduje vse elemente
svojega nadrazreda, je objekt izpeljanega svojega nadrazreda, je objekt izpeljanega razreda hkrati tudi objekt nadrazreda. Obratno razreda hkrati tudi objekt nadrazreda. Obratno pa ne velja,pa ne velja, kajti objektu nadrazreda manjkajo kajti objektu nadrazreda manjkajo podatki in metode, ki so definirani v podatki in metode, ki so definirani v izpeljanem razredu.izpeljanem razredu.
Primer izpeljave Primer izpeljave razreda student iz razreda student iz razreda oseba:razreda oseba:
Razred student predstavlja Razred student predstavlja sprecializacijo razreda oseba.sprecializacijo razreda oseba.
K podatkom o določeni osebi bomo K podatkom o določeni osebi bomo torej dodali podatke,torej dodali podatke,ki določajo, da ki določajo, da je ta oseba pravzaprav študent. je ta oseba pravzaprav študent. ZaradiZaradi enostavnosti smo izbrali enostavnosti smo izbrali podatek "smer", ki predstavljapodatek "smer", ki predstavlja smer študija posameznega smer študija posameznega študenta.študenta.
#include<iostream.h>#include<iostream.h>
enum spol {moski, zenski};enum spol {moski, zenski};
class osebaclass oseba
{{
public:public:
oseba(char im[], char p[], spol s, char dat_r[]);oseba(char im[], char p[], spol s, char dat_r[]);
oseba() {};oseba() {};
void Vpisi();void Vpisi();
void Izpisi();void Izpisi();
private:private:
char ime[15];char ime[15];
char priimek[15];char priimek[15];
spol spol_o;spol spol_o;
char datum_r[10];char datum_r[10];
};};
class student : public osebaclass student : public oseba
{{
public:public:
void Vpisi();void Vpisi();
void Izpisi();void Izpisi();
private:private:
char smer[20];char smer[20];
};};
Beseda Beseda publicpublic, ki je zapisana pri izpeljavi nam pove, da so , ki je zapisana pri izpeljavi nam pove, da so javni ("public") elementi nadrazreda (oseba) javni tudi v javni ("public") elementi nadrazreda (oseba) javni tudi v izpeljanem razredu (student).izpeljanem razredu (student).
oseba :: oseba(char im[], char p[], spol s, char dat_r[])oseba :: oseba(char im[], char p[], spol s, char dat_r[])
{{
for (int i=0; i<15; i++)for (int i=0; i<15; i++)
ime[i] = im[i];ime[i] = im[i];
for (i=0; i<15; i++)for (i=0; i<15; i++)
priimek[i] = p[i];priimek[i] = p[i];
spol_o = s;spol_o = s;
for (i=0; i<10; i++)for (i=0; i<10; i++)
datum_r[i] = dat_r[i];datum_r[i] = dat_r[i];
}}
void oseba :: Vpisi()void oseba :: Vpisi()
{{
int sp;int sp;
cout << endl;cout << endl;
cout << " Vpisi ime: ";cout << " Vpisi ime: ";
cin >> ime;cin >> ime;
cout << " Vpisi priimek: ";cout << " Vpisi priimek: ";
cin >> priimek;cin >> priimek;
cout << " Vpisi spol 1 - zenski, 2 - moski: ";cout << " Vpisi spol 1 - zenski, 2 - moski: ";
cin >> sp;cin >> sp;
if (sp == 1)if (sp == 1)
spol_o = zenski;spol_o = zenski;
elseelse
spol_o = moski;spol_o = moski;
cout << " Vpisi datum rojstva: ";cout << " Vpisi datum rojstva: ";
cin >> datum_r;cin >> datum_r;
}}
void student :: Vpisi()void student :: Vpisi()
{{
cout << " Vpisi smer: ";cout << " Vpisi smer: ";
cin >> smer;cin >> smer;
}}
void oseba :: Izpisi()void oseba :: Izpisi()
{{
cout << endl << " Ime: " << ime;cout << endl << " Ime: " << ime;
cout << endl << " Priimek: " << priimek;cout << endl << " Priimek: " << priimek;
if (spol_o == zenski)if (spol_o == zenski)
cout << endl << " Spol: Zenski";cout << endl << " Spol: Zenski";
elseelse
cout << endl << " Spol: Moski";cout << endl << " Spol: Moski";
cout << endl << " Datum rojstva: " << datum_r << endl;cout << endl << " Datum rojstva: " << datum_r << endl;
}}
void student :: Izpisi()void student :: Izpisi()
{{
cout << " Smer: " << smer << endl;cout << " Smer: " << smer << endl;
}}
int main()int main()
{{
student luka;student luka;
luka.oseba::Vpisi();luka.oseba::Vpisi();
luka.Vpisi();luka.Vpisi();
luka.oseba::Izpisi();luka.oseba::Izpisi();
luka.Izpisi();luka.Izpisi();
return 0;return 0;
}}
ZašZašččiteni elementiiteni elementi
Poleg javnih in privatnih elementov lahko v razredih Poleg javnih in privatnih elementov lahko v razredih definiramo tudi zaščitene elemente z določilom definiramo tudi zaščitene elemente z določilom protectedprotected. .
ZašZašččiteniiteni elementielementi so vmesna stopnja med javnimi in so vmesna stopnja med javnimi in
privatnimi elementi. Do privatnimi elementi. Do javnihjavnih elementovelementov nekega nekega razreda lahko z objektom tega razreda dostoparazreda lahko z objektom tega razreda dostopa kdorkoli kdorkoli v programu. v programu.
Do Do privatnihprivatnih elementovelementov nekega razreda lahko nekega razreda lahko
dostopajo samo ta razred in njegovi prijatelji. dostopajo samo ta razred in njegovi prijatelji.
Do Do zaščitenihzaščitenih elementovelementov nekega razreda lahko nekega razreda lahko dostopajo enako kot dodostopajo enako kot do privatnih elementov ta razred in privatnih elementov ta razred in njegovi prijatelji,njegovi prijatelji, poleg tega pa še vsi izpeljani razredi in poleg tega pa še vsi izpeljani razredi in prijatelji teprijatelji teh h razredov.razredov.
Tipi izpeljavTipi izpeljav
Izpeljavo, v kateri uporabimo kljuIzpeljavo, v kateri uporabimo ključčno besedo public, kot no besedo public, kot npr. v primeru:npr. v primeru:
class student : public osebaclass student : public oseba imenujemo imenujemo javnajavna izpeljavaizpeljava. . Poleg te ima jezik C++ še Poleg te ima jezik C++ še
zaščitenozaščiteno in in privatnoprivatno izpeljavo. izpeljavo. Ta dva tipa izpeljav Ta dva tipa izpeljav določimo s ključnima besedama protected in private:določimo s ključnima besedama protected in private:
class student : protected osebaclass student : protected osebainin
class student : private osebaclass student : private oseba
Tipi izpeljavTipi izpeljav
Zaščitena in privatna izpeljava v Zaščitena in privatna izpeljava v izpeljanih razredih omejita dostop izpeljanih razredih omejita dostop do zaščitenih in javnih elementov do zaščitenih in javnih elementov nadrazreda. Dostop do elementov nadrazreda. Dostop do elementov nadrazreda nadrazreda je predstavljen v je predstavljen v naslednji tabeli:naslednji tabeli:
Tipi izpeljavTipi izpeljav
privateprivateprivateprivate
privateprotectedprotected
protected
privateprotectedpublicpublic
privateprotected
public
Tip izpeljave
Tip izpeljave
Tip izpeljave
tip elementa
Tipi izpeljavTipi izpeljav
Podatki v tabeli povedo, kakšen je Podatki v tabeli povedo, kakšen je dostop do elementa nadrazreda v dostop do elementa nadrazreda v izpeljanih razredih, če imamo izpeljanih razredih, če imamo podan tip elementa in tip izpeljave. podan tip elementa in tip izpeljave. Pri Pri zaščiteni izpeljavizaščiteni izpeljavi se javni se javni elementi nadrazreda obravnavajo elementi nadrazreda obravnavajo kotkot zaščiteni elementi, prizaščiteni elementi, pri privatniprivatni izpeljaviizpeljavi pa se javni in zaš pa se javni in zašččiteni iteni elementi obravnavajo kot privatnielementi obravnavajo kot privatni elementi.elementi.
POLIMORFIZEMPOLIMORFIZEM
DedovanjeDedovanje in in polimorfizempolimorfizem sta dve sta dve
najpomembnejši lastnosti objektnega najpomembnejši lastnosti objektnega programiranja. Prvo smo že spoznali, programiranja. Prvo smo že spoznali, druga pa označuje princip, da lahko druga pa označuje princip, da lahko različni objekti razumejo isto sporočilo različni objekti razumejo isto sporočilo in se nanj odzovejo vsak na svoj način. in se nanj odzovejo vsak na svoj način. Obe lastnosti sta osnova objektnega Obe lastnosti sta osnova objektnega programiranja in omogočata hitrejši programiranja in omogočata hitrejši razvoj in lažje vzdrževanje programske razvoj in lažje vzdrževanje programske kode.kode.
Polimorfizem - primerPolimorfizem - primer
Imejmo poleg razreda Imejmo poleg razreda studentstudent, iz razreda , iz razreda oseba oseba izpeljana še razreda izpeljana še razreda profesor profesor in in asistentasistent. Oba naj imata po en dodaten . Oba naj imata po en dodaten element: profesor naj ima predmet, ki ga element: profesor naj ima predmet, ki ga poučuje, asistent pa predmet, pri katerem ima poučuje, asistent pa predmet, pri katerem ima vaje. Vsak od njiju ima svojo inačico metode vaje. Vsak od njiju ima svojo inačico metode izpiši, ki izpiše podatke tega objekta.izpiši, ki izpiše podatke tega objekta.
Oglejmo si primer, ko želimo vnašati in Oglejmo si primer, ko želimo vnašati in
izpisovati več objektov tipa študent, asistent izpisovati več objektov tipa študent, asistent ali profesor. Za shranjevanje bomo uporabili ali profesor. Za shranjevanje bomo uporabili polje kazalcev. Ker ne vemo kakšne elemente polje kazalcev. Ker ne vemo kakšne elemente bomo gradili (ta podatek bo znan šele v bomo gradili (ta podatek bo znan šele v izvajanju), bomo shranjevali kazalce na skupni izvajanju), bomo shranjevali kazalce na skupni nadrazred.nadrazred.
#include "student.h"#include "student.h"
#include "asistent.h"#include "asistent.h"
#include "profesor.h"#include "profesor.h"
#include <iostream.h>#include <iostream.h>
const int max_oseb = 4;const int max_oseb = 4;
int main()int main()
{{
oseba* ptr_polje_oseb[max_oseb];oseba* ptr_polje_oseb[max_oseb]; //polje za shranjevanje oseb //polje za shranjevanje oseb
oseba* ptr_začasna;oseba* ptr_začasna;
cout << "Vnesi " << max_oseb << " osebe !" << endl;cout << "Vnesi " << max_oseb << " osebe !" << endl;
char tip_osebe[];char tip_osebe[];
char ime[vel_ime];char ime[vel_ime];
char naslov[vel_naslov];char naslov[vel_naslov];
char smer[vel_smer];char smer[vel_smer];
char vaje[vel_vaje];char vaje[vel_vaje];
char predmet[vel_predmet];char predmet[vel_predmet];
for (int i = 0; i < max_oseb; i++)for (int i = 0; i < max_oseb; i++)
{{
cout << endl << endl << "Vnesi tip osebe (S, A, P): ";cout << endl << endl << "Vnesi tip osebe (S, A, P): ";
cin >> tip_osebe;cin >> tip_osebe;
cout << "Vnesi imecout << "Vnesi ime : ";: ";
cin << ime;cin << ime;
cout << "Vnesi naslovcout << "Vnesi naslov : ";: ";
cin >> naslov;cin >> naslov;
if (tip_osebe == 'S')if (tip_osebe == 'S')
{{
cout << "Smer studenta cout << "Smer studenta : ";: ";
cin >> smer;cin >> smer;
ptr_zacasna = new student (ime, naslov, smer);ptr_zacasna = new student (ime, naslov, smer);
}}
else if (tip_osebe == 'A')else if (tip_osebe == 'A')
{{
cout << "Predmet asistenta cout << "Predmet asistenta : ";: ";
cin >> vaje;cin >> vaje;
ptr_zacasna = new asistent (ime, naslov, vaje);ptr_zacasna = new asistent (ime, naslov, vaje);
}}
else if (tip_osebe == 'P')else if (tip_osebe == 'P')
{{
cout << "Predmet profesorja cout << "Predmet profesorja : ";: ";
cin >> vaje;cin >> vaje;
ptr_zacasna = new profesor (ime, naslov, predmet);ptr_zacasna = new profesor (ime, naslov, predmet);
}}
elseelse
{{
cout << "Napacen tip osebe!" << endl;cout << "Napacen tip osebe!" << endl;
cout << "Ustvarilo bom objekt razreda oseba!";cout << "Ustvarilo bom objekt razreda oseba!";
ptr_zacasna = new oseba (ime, naslov);ptr_zacasna = new oseba (ime, naslov);
}}
ptr_polje_oseb[i] = ptr_zacasna;ptr_polje_oseb[i] = ptr_zacasna;
}}
//izpis vnesenih oseb//izpis vnesenih oseb
for (i = 0; i < max_oseb; i++)for (i = 0; i < max_oseb; i++)
{{
ptr_polje_oseb[i] ->izpisi();ptr_polje_oseb[i] ->izpisi();
cout << endl;cout << endl;
}}
//brisanje polja kazalcev//brisanje polja kazalcev
for (i = 0; i < max_oseb; i++)for (i = 0; i < max_oseb; i++)
delete ptr_polje_oseb[i];delete ptr_polje_oseb[i];
return 0;return 0;
}}
Razložimo program! Najprej v zanki preberemo tip osebe ter Razložimo program! Najprej v zanki preberemo tip osebe ter ime in naslov osebe. Glede na tip osebe preberemo še ime in naslov osebe. Glede na tip osebe preberemo še smer, vaje ali predmet in ustvarimo objekt ustreznega smer, vaje ali predmet in ustvarimo objekt ustreznega razreda s pomočjo operatorja razreda s pomočjo operatorja newnew. Ta nam vrne kazalec na . Ta nam vrne kazalec na objekt (objekt (student*student* ali ali asistent*asistent* oz. oz. profesor*profesor*). Ta kazalec ). Ta kazalec shranimo v spremenljivko shranimo v spremenljivko ptr_zacasnaptr_zacasna, ki pa je tipa , ki pa je tipa oseba*.oseba*. Kako lahko to storimo? To je mogoče zato, ker je Kako lahko to storimo? To je mogoče zato, ker je vsak študent (oz. asistent ali profesor) tudi oseba, zato vsak študent (oz. asistent ali profesor) tudi oseba, zato lahko napravimo pretvorbo kazalca: npr. lahko napravimo pretvorbo kazalca: npr. student*student* v v oseba*oseba*. Pretvorba se napravi implicitno pri operatorju . Pretvorba se napravi implicitno pri operatorju newnew. . Pretvorbo bi lahko zahtevali tudi eksplicitno z naslednjim Pretvorbo bi lahko zahtevali tudi eksplicitno z naslednjim zapisom:zapisom:
ptr_zacasna = (oseba*)new student(ime,naslov,smer);ptr_zacasna = (oseba*)new student(ime,naslov,smer);
Kadar kot tip osebe vnesemo nepravilno vrednost, Kadar kot tip osebe vnesemo nepravilno vrednost, ustvarimo objekt tipa oseba. Ko smo vnesli vse osebe, jih ustvarimo objekt tipa oseba. Ko smo vnesli vse osebe, jih še izpišemo in nato zbrišemo (sproščanje dinamično še izpišemo in nato zbrišemo (sproščanje dinamično dodeljenega pomnilnika!).dodeljenega pomnilnika!).
Prikaz delovanja programa:Prikaz delovanja programa:
Vnesi 4 osebe!Vnesi 4 osebe!
Vnesi tip osebe (S, A, P): SVnesi tip osebe (S, A, P): S
Vnesi imeVnesi ime : Janez: Janez
Vnesi naslovVnesi naslov : Mladinska: Mladinska
Smer studentaSmer studenta : Anglescina: Anglescina
Vnesi tip osebe (S, A, P): AVnesi tip osebe (S, A, P): A
Vnesi imeVnesi ime : Metka: Metka
Vnesi naslovVnesi naslov : Slovenska: Slovenska
Predmet asistentaPredmet asistenta : Nemscina: Nemscina
Vnesi tip osebe (S, A, P): PVnesi tip osebe (S, A, P): P
Vnesi imeVnesi ime : France: France
Vnesi naslovVnesi naslov : Ljubljanska: Ljubljanska
Predmet profesorjaPredmet profesorja : Računalnistvo: Računalnistvo
Vnesi tip osebe (S, A, P): kVnesi tip osebe (S, A, P): k
Vnesi imeVnesi ime : Marija: Marija
Vnesi naslovVnesi naslov : Betnavska: Betnavska
Napacen tip osebe!Napacen tip osebe!
Ustvaril bom objekt razreda oseba!Ustvaril bom objekt razreda oseba!
Ime osebeIme osebe : Janez: Janez
NaslovNaslov : Mladinska: Mladinska
Ime osebeIme osebe : Metka: Metka
NaslovNaslov : Slovenska: Slovenska
Ime osebeIme osebe : France: France
NaslovNaslov : Ljubljanska: Ljubljanska
Ime osebeIme osebe : Marija: Marija
NaslovNaslov : Betnavska: Betnavska
Polimorfna redefinicijaPolimorfna redefinicija
Če si ogledamo izpis programa opazimo, da so se za Če si ogledamo izpis programa opazimo, da so se za vsak vnešeni objekt izpisali samo podatki, ki so zapisani vsak vnešeni objekt izpisali samo podatki, ki so zapisani v razredu v razredu osebaoseba in ne vsi podatki študenta, asistenta in in ne vsi podatki študenta, asistenta in profesorja. Zakaj?profesorja. Zakaj?
Ko smo objekte shranjevali, smo kazalec pretvorili v tip Ko smo objekte shranjevali, smo kazalec pretvorili v tip oseba*oseba*. Ko kličemo metodo . Ko kličemo metodo izpisiizpisi, zato kličemo , zato kličemo metodo metodo oseba::izpisioseba::izpisi. Vidimo, da navadna redefinicija . Vidimo, da navadna redefinicija metode v tem primeru ne zadošča. Čeprav imamo samo metode v tem primeru ne zadošča. Čeprav imamo samo kazalce na razred kazalce na razred osebaoseba, želimo, da vsak objekt ohrani , želimo, da vsak objekt ohrani sebi lastno obnašanje ob klicu metode sebi lastno obnašanje ob klicu metode izpisiizpisi. . Uporabiti moramo Uporabiti moramo polimorfno redefinicijopolimorfno redefinicijo. .
Polimorfna redefinicijaPolimorfna redefinicija
Polimorfno redefinicijo omogočimo z definicijo Polimorfno redefinicijo omogočimo z definicijo virtualnevirtualne metode. Metodo metode. Metodo izpisiizpisi moramo v moramo v razredu razredu osebaoseba definirati kot virtualno, kar definirati kot virtualno, kar storimo na naslednji način:storimo na naslednji način:
virtual void izpisi() const;virtual void izpisi() const;
Ta definicija pove, da naj izpeljani objekt kliče Ta definicija pove, da naj izpeljani objekt kliče
svojo funkcijo svojo funkcijo izpisiizpisi, čeprav bi bil klic izvršen , čeprav bi bil klic izvršen preko kazalca na nadrazred (preko kazalca na nadrazred (oseba*oseba*). Ob ). Ob takšni definiciji metode takšni definiciji metode izpisiizpisi v razredu v razredu osebaoseba, bo prejšnji primer izpisal naslednje:, bo prejšnji primer izpisal naslednje:
Vnesi 4 osebe!Vnesi 4 osebe!
Vnesi tip osebe (S, A, P): SVnesi tip osebe (S, A, P): S
Vnesi imeVnesi ime : Janez: Janez
Vnesi naslovVnesi naslov : Mladinska: Mladinska
Smer studentaSmer studenta : Anglescina: Anglescina
Vnesi tip osebe (S, A, P): AVnesi tip osebe (S, A, P): A
Vnesi imeVnesi ime : Metka: Metka
Vnesi naslovVnesi naslov : Slovenska: Slovenska
Predmet asistentaPredmet asistenta : Nemscina: Nemscina
Vnesi tip osebe (S, A, P): PVnesi tip osebe (S, A, P): P
Vnesi imeVnesi ime : France: France
Vnesi naslovVnesi naslov : Ljubljanska: Ljubljanska
Predmet profePredmet profesorjasorja : Računalnistvo: Računalnistvo
Vnesi tip osebe (S, A, P): kVnesi tip osebe (S, A, P): k
Vnesi imeVnesi ime : Marija: Marija
Vnesi naslovVnesi naslov : Betnavska: Betnavska
Napacen tip osebe!Napacen tip osebe!
Ustvaril bom objekt razreda oseba!Ustvaril bom objekt razreda oseba!
Ime osebeIme osebe : Janez: Janez
NaslovNaslov : Mladinska: Mladinska
SmerSmer : Angleščina: Angleščina
Ime osebeIme osebe : Metka: Metka
NaslovNaslov : Slovenska: Slovenska
Vaje priVaje pri : Nemščina: Nemščina
Ime osebeIme osebe : France: France
NaslovNaslov : Ljubljanska: Ljubljanska
PredmetPredmet : Računalništvo: Računalništvo
Ime osebeIme osebe : Marija: Marija
NaslovNaslov : Betnavska: Betnavska
Polimorfna redefinicijaPolimorfna redefinicija
Problem se pojavi tudi pri brisanju Problem se pojavi tudi pri brisanju dinamično alociranih objektov. dinamično alociranih objektov. Pri klicu Pri klicu operatorja operatorja deletedelete se bo klical se bo klical destruktor za razred destruktor za razred osebaoseba namesto namesto destruktor ustreznega objekta. destruktor ustreznega objekta. Zato Zato moramo tudi destruktor definirati kot moramo tudi destruktor definirati kot virtualno metodo:virtualno metodo:
virtual ~oseba();virtual ~oseba();
Abstraktni razrediAbstraktni razredi
Včasih imamo hierarhijo razredov, v kateri imamo Včasih imamo hierarhijo razredov, v kateri imamo nadrazred, za katerega vemo, da ne bomo uporabljali nadrazred, za katerega vemo, da ne bomo uporabljali objektov tega razreda. Tak razred hočemo imeti v objektov tega razreda. Tak razred hočemo imeti v hierarhiji samo zaradi definicije polimorfnega obnašanja hierarhiji samo zaradi definicije polimorfnega obnašanja nekaterih funkcij. Take razrede imenujemo nekaterih funkcij. Take razrede imenujemo abstraktni abstraktni razredirazredi. Primeri takih abstraktnih razredov so lahko na . Primeri takih abstraktnih razredov so lahko na primer primer oblikaoblika, , telotelo, , liklik, ..., ...
Razred napravimo abstrakten tako, da definiramo vsaj Razred napravimo abstrakten tako, da definiramo vsaj
eno izmed njegovih metod kot eno izmed njegovih metod kot čisto virtualnočisto virtualno ( (pure pure virtual functionvirtual function). Funkcija je čisto virtualna, kadar za ). Funkcija je čisto virtualna, kadar za definicijo vsebuje še inicializacijo = 0.definicijo vsebuje še inicializacijo = 0.
Čisto virualne funkcijeČisto virualne funkcije
virtual void izracunaj_ploscino() const = 0;virtual void izracunaj_ploscino() const = 0;
Funkcijo Funkcijo izracunaj_ploscinoizracunaj_ploscino lahko napravimo čisto virtualno lahko napravimo čisto virtualno za razred za razred liklik. Funkcija omogoča polimorfno definicijo funkcije . Funkcija omogoča polimorfno definicijo funkcije za vsakega izmed izpeljanih razredov, hkrati pa definira razred za vsakega izmed izpeljanih razredov, hkrati pa definira razred liklik kot abstraktni razred, ki ga ne moremo uporabiti za kot abstraktni razred, ki ga ne moremo uporabiti za tvorjenje objektov. To tudi pomeni, da moramo funkcijo tvorjenje objektov. To tudi pomeni, da moramo funkcijo izracunaj_ploscinoizracunaj_ploscino redefinirati v vsakem razredu, ki ga redefinirati v vsakem razredu, ki ga izpeljemo iz razreda izpeljemo iz razreda liklik – kar pa je tudi smiselno, saj v – kar pa je tudi smiselno, saj v razredu razredu liklik nimamo podatkov za izračun ploščine. nimamo podatkov za izračun ploščine.
Čisto virtualne funkcije moramo redefinirati v vseh izpeljanih Čisto virtualne funkcije moramo redefinirati v vseh izpeljanih razredih, navadne virtualne pa ne. Kadar izpeljani razred nima razredih, navadne virtualne pa ne. Kadar izpeljani razred nima redefinirane navadne virtualne funkcije, se bo klicala funkcija redefinirane navadne virtualne funkcije, se bo klicala funkcija nadrazreda.nadrazreda.
VeVeččkratno dedovanjekratno dedovanje
Razred je lahko izpeljan tudi iz več Razred je lahko izpeljan tudi iz več kot enega razreda. V tem primeru kot enega razreda. V tem primeru govorimo o večkratnem govorimo o večkratnem dedovanju. Definirajmo razred dedovanju. Definirajmo razred student_asistentstudent_asistent, ki naj , ki naj predstavlja osebe, ki so hkrati predstavlja osebe, ki so hkrati študentje in asistentje.študentje in asistentje.
#include "student.h"#include "student.h"
#include "asistent.h"#include "asistent.h"
class student_asistent : public student, public class student_asistent : public student, public asistentasistent
{{
public:public:
student_asistent (char i[], char n[], char s[], student_asistent (char i[], char n[], char s[], char v[]);char v[]);
void izpisi() const;void izpisi() const;
}}
V konstruktorju razreda V konstruktorju razreda student_asistent student_asistent sedaj podamo sedaj podamo ime, naslov, poleg tega pa še smer in predmet. Oglejmo si ime, naslov, poleg tega pa še smer in predmet. Oglejmo si definicijo konstruktorjev in metode definicijo konstruktorjev in metode izpisi()izpisi()..
#include <iostream.h>#include <iostream.h>
student_asistent :: student_asistent (char i, char n, char s, student_asistent :: student_asistent (char i, char n, char s, char v)char v)
: student (i, n, s), asistent ("---", "+++" , v) {}: student (i, n, s), asistent ("---", "+++" , v) {}
void student_asistent :: izpisi() constvoid student_asistent :: izpisi() const
{{
student::izpisi();student::izpisi();
cout << endl;cout << endl;
asistent::izpisi();asistent::izpisi();
}}
Večkratno dedovanjeVečkratno dedovanje
Z večkratnim dedovanjem dobi Z večkratnim dedovanjem dobi razred več primerkov nadrazredov:razred več primerkov nadrazredov:
oseba
student asistent
student_asistent
Večkratno dedovanjeVečkratno dedovanje
V našem primeru je razred V našem primeru je razred student_asistentstudent_asistent izpeljan iz razredov izpeljan iz razredov studentstudent in in asistentasistent, ta , ta dva pa sta izpeljana iz razreda dva pa sta izpeljana iz razreda osebaoseba. Objekt . Objekt tipa tipa student_asistent student_asistent v tem primeru v tem primeru vsebuje dva objekta tipa vsebuje dva objekta tipa osebaoseba, ki sta med , ki sta med seboj neodvisna in lahko vsebujeta različne seboj neodvisna in lahko vsebujeta različne podatke. Različne podatke v obeh objektih tipa podatke. Različne podatke v obeh objektih tipa oseba lahko dosežemo tako, da oseba lahko dosežemo tako, da konstruktorjema nadrazredov konstruktorjema nadrazredov studentstudent in in asistentasistent podamo različne argumente: podamo različne argumente:
: student (i, n, s), asistent ("---", "+++" , v): student (i, n, s), asistent ("---", "+++" , v)
#include <iostream.h>#include <iostream.h>
#include "student_asistent.h"#include "student_asistent.h"
#include "profesor.h"#include "profesor.h"
int main()int main()
{{
student sosolec("Janez", "Ljubljanska 12", "Računalništvo");student sosolec("Janez", "Ljubljanska 12", "Računalništvo");
cout << "Student sosolec" << endl;cout << "Student sosolec" << endl;
sosolec.izpisi();sosolec.izpisi();
cout << endl << endl;cout << endl << endl;
student_asistent sosed("Peter", "Mariborska 23", student_asistent sosed("Peter", "Mariborska 23",
"Programska oprema", "Programiranje ");"Programska oprema", "Programiranje ");
cout << "Student-asistent sosed" << endl;cout << "Student-asistent sosed" << endl;
sosed.izpisi();sosed.izpisi();
cout << endl;cout << endl;
return 0;return 0;
}}
Program izpiše:Program izpiše:
Student sosolecStudent sosolec
Ime osebeIme osebe : Janez: Janez
NaslovNaslov : Ljubljanska 12: Ljubljanska 12
SmerSmer : : RačunalništvoRačunalništvo
Student-asistent sosedStudent-asistent sosed
Ime osebeIme osebe : Peter: Peter
NaslovNaslov : Mariborska 23: Mariborska 23
SmerSmer : Programska oprema: Programska oprema
Ime osebeIme osebe : ---: ---
NaslovNaslov : +++: +++
VajeVaje : Programiranje: Programiranje
Večkratno dedovanjeVečkratno dedovanje
Če v razredu Če v razredu student_asistent student_asistent ne ne definiramo metode za izpis definiramo metode za izpis izpisi()izpisi(), , je klic je klic sosed.izpisi()sosed.izpisi() napačen, saj napačen, saj prevajalnik ne ve, katero od metod prevajalnik ne ve, katero od metod izpisi()izpisi() naj kliče; tisto, ki je v razredu naj kliče; tisto, ki je v razredu student student ali tisto, ki je v razredu ali tisto, ki je v razredu asistentasistent. V tem primeru moramo sami . V tem primeru moramo sami navesti nadrazred, katerega metoda za navesti nadrazred, katerega metoda za izpis se naj kliče: izpis se naj kliče: student::izpisi()student::izpisi() ali ali asistent::izpisi()asistent::izpisi()..
Virtualni nadrazrediVirtualni nadrazredi Ugotovili smo, da se v razredih pri večkratnem Ugotovili smo, da se v razredih pri večkratnem
dedovanju podatki podvajajo. Včasih je to potrebno, v dedovanju podatki podvajajo. Včasih je to potrebno, v večini primerov pa se želimo nepotrebnemu podvajanju večini primerov pa se želimo nepotrebnemu podvajanju podatkov izogniti. podatkov izogniti. V ta namen lahko definiramo V ta namen lahko definiramo virtualne nadrazrede virtualne nadrazrede ((virtual base classesvirtual base classes).).
Kot virtualni nadrazred definiramo tisti razred, za Kot virtualni nadrazred definiramo tisti razred, za katerega predvidevamo, da se bo uporabljal kot katerega predvidevamo, da se bo uporabljal kot nadrazred za večkratno dedovanje. V našem primeru nadrazred za večkratno dedovanje. V našem primeru definiramo kot virtualni nadrazred, razred oseba. Zato definiramo kot virtualni nadrazred, razred oseba. Zato zapišemo izpeljavo tazredov student, asistent in zapišemo izpeljavo tazredov student, asistent in profesor na naslednji način:profesor na naslednji način:
class student :: public virtual osebaclass student :: public virtual oseba
Takšno izpeljavo imenujemo tudi virtualna izpeljava. Takšno izpeljavo imenujemo tudi virtualna izpeljava.
Poglejmo grafično predstavitev objekta razreda Poglejmo grafično predstavitev objekta razreda student_asistent pri navadni in virtualni izpeljavi:student_asistent pri navadni in virtualni izpeljavi:
OSEBASTUDENT
OSEBAASISTENT
STUDENT
OSEBA
ASISTENT
Navadna izpeljava Virtualna izpeljava
VIRTUALNA IZPELJAVAVIRTUALNA IZPELJAVA
Spremeniti pa je potrebno tudi Spremeniti pa je potrebno tudi konstruktor razreda konstruktor razreda student_asistent:student_asistent:
student_asistent :: student_asistent :: student_asistent (char i, char n, student_asistent (char i, char n, char s, char v)char s, char v)
: oseba(i, n), student (i, n, s), : oseba(i, n), student (i, n, s), asistent ("---", "+++" , v) {}asistent ("---", "+++" , v) {}