Előadást letölteni
Az előadás letöltése folymat van. Kérjük, várjon
KiadtaErnő Veres Megváltozta több, mint 6 éve
1
Öröklés bemutatása Hozzunk létre egy Dolgozó adatbázist C++-ban!
Definiáljunk egy osztályt, amely a közös tulajdonságokat tartalmazza. 1
2
Osztály hierarchia 2
3
Tulajdonságok Órabéres dolgozó: Ügynök Menedzser Órabér Óraszám
Jutalék Típus Menedzser Heti fizetés
4
Osztály megvalósítása C++-ban
class Dolgozo { public: Dolgozo(); Dolgozo( char *nm); char *getName () {return nev;} private: char nev[30]; }; 3
5
Alaposztály: közös tulajdonságok
A Dolgozo csak a nevet tárolja, de tárolhatna több tulajdonságot is. Például: születési idő, cím stb. 4
6
Származtatott osztály
Ezután definiáljunk egy olyan osztályt, amely a dolgozónak egy különleges típusa: órabérben dolgozik. Két lehetőség OraberesDolgozo adattagként tárolja a Dolgozo osztályt Az OraberesDolgozo osztályt a Dolgozo osztályból származtatjuk. 5
7
A származtatás szintaxisa
class OraberesDolgozo : public Dolgozo { public: OraberesDolgozo(char *nm); void setOradij( float ora_d); void setOraszam(float ora_sz); private: float oradij; float oraszam; }; 6
8
Osztályok típusai Dolgozo: alaposztály (base class) OraberesDolgozo:
származtatott osztály ( derived class) 7
9
Példa: Objektumok definiálása és műveletek
OraberesDolgozo aDolgozo (“Kovács István”); char *str; aDolgozo.setOraszam(40.0); //OraberesDolgozo: setOraszam(); aDolgozo.setOradij(8.0); //OraberesDolgozo: setOradij(); str=aDolgozo.getname(); //Dolgozo:getname(); 8
10
Objektumok helyfoglalása
9
11
privat adattagok használata
A származtatott osztályok tagfüggvényei nem használhatják a bázis osztály privát adattagjait. Például: void OraberesDolgozo: printName() { cout <<”Dolgozó neve” << name << ’\n’; } ehelyett Dolgozo:getName() 10
12
Oka ha bárki származtat osztályokat és azzal dolgozik, majd a bázisosztály megváltozik, akkor minden származtatott osztályban meg kellene változtatni az adatok kezelését! (Encapsulation!!!) 11
13
További származtatás class Ugynok : public OraberesDolgozo { public:
Ugynok(char *nm); void setJutalek (float j_alap); void setTipus (float j_tipus); private: float jutalek; float tipus; }; 12
14
Ugynok osztály tulajdonságai
Ügynök fizetése: órabéren kívül jutalékot kap, aszerint, hogy milyen típusba van besorolva. Egy Ugynok objektum minden olyan adattagot tartalmaz, amelyet a Dolgozo-ban és az OraberesDolgozo-ban, illetve az Ugynok-ben van definiálva. Egy Ugynok objektumra az összes olyan tagfüggvényt hívhatjuk, amely ebben a három osztályban lett definiálva. 13
15
Osztályhierarchia OraberesDolgozo alaposztály származtatott osztály is
14
16
Menedzser származtatása
class Menedzser : public Dolgozo { public: Menedzser (char *nm); void setHetiFizetes( float fizetes); private: float heti_fizetes; }; 15
17
Tagfüggvények újradefiniálása
Ezek után definiáljuk az egyes dolgozó típusokhoz a heti fizetések kiszámítását végző függvényeket! float OraberesDolgozo::computePay() { return oraszam * oradij; } 16
18
float Ugynok::computePay() //ez újradefiniálás {
return oraszam * oradij + jutalek * tipus; } ez nem jó, mert private tagok - oraszam*oradij helyett computePay() szintén nem jó, mert rekurzív hívás lenne OraberesDolgozo::computePay() jó 17
19
Nem újradefiniálás float Menedzser:computePay() //ez nem újradefiniálás, mert a Menedzser osztály nem leszármazottja egyiknek sem { return heti_fizetes; } 18
20
Származtatott osztályok tagfüggvényei
Egy származtatott osztály egy előfordulása tartalmazza az alaposztály és a bázisosztály mindegyik adattagját. Egy származtatott osztály konstruktora meg kell, hogy hívja a bázisosztály konstruktorát. 19
21
Konstruktorok OraberesDolgozo :: OraberesDolgozo (char *nm): Dolgozo(nm) { oradij = 0.0.; oraszam = 0.0.; }; 20
22
Konstruktorok Ugynok :: Ugynok (char *nm) : OraberesDolgozo (nm) {
jutalek = 0.0; tipus = 0.0; } 21
23
Konstruktorok Menedzser :: Menedzser (char *nm) : Dolgozo (nm) {
heti_fizetes = 0.0; } 22
24
Konverzió bázis és származtatott osztályok között
OraberesDolgozo aDolgozo; Ugynok aUgynok (“Kovács István”); aDolgozo = aUgynok; // jó! aUgynok = aDolgozo; //nem jó! 23
25
Objektumok és pointereik
Dolgozo *DolgPtr; OraberesDolgozo aOraberesDolgozo (“Kiss Lajos”); Ugynok aUgynok (“Kovács István”); Menedzser aFonok (“Nagy Lajos”); DolgPtr = &aDolgozo; //Implicit konverzió DolgPtr = &aUgynok; //Dolgozo-ra DolgPtr = &Fonok; 24
26
Objektumok és pointereik
Ugynok aUgynok (“Kovács István”); Ugynok *UgynokPtr; OraberesDolgozo *OraberesPtr; UgynokPtr = &aUgynok; OraberesPtr = & aUgynok; 25
27
OraberesPtr -> setOrak(40.0); // OraberesDolgozo:setOrak
OraberesPtr -> setOradij(6.0); // OraberesDolgozo:setOradij OraberesPtr -> setTipus (1000.0); //Hiba nincs ilyen tagfüggvény // OraberesDolgozo:setTipus UgynokPtr -> setTipus (1000.0); // Ugynok: setTipus UgynokPtr -> setJutalek (0.05); // Ugynok: setJutalek 26
28
Származtatott osztályok tagfüggvényei
Ha egy olyan tagfüggvényt hívunk meg, amely a bázis és a származtatott osztályban is definiálva van, akkor a pointer típusától függ, hogy melyiket hajtjuk végre. float base, total; base = OraberesPtr -> computePay(); // OraberesDolgozo: computePay(); total = UgynokPtr -> computePay(); // Ugynok: computePay(); 27
29
Virtuális függvények class Dolgozo kiegészítése egy tagfüggvénnyel
virtual float computePay() ; 28
30
Tagfüggvények Minden osztályt kiegészítünk ezzel a tagfüggvénnyel:
float computePay() ; 29
31
Tagfüggvény definiálása
float Dolgozo:: float computePay() { cout << "Nem számít fizetést!\n"; return 0.0. ; } 30
32
DolgPtr = &aOraberesDolgozo;
Mi történik, ha a float computePay() -t egy Dolgozo típusú pointeren keresztül hívjuk meg? DolgPtr = &aOraberesDolgozo; fizetes = DolgPtr -> computePay(); // OraberesDolgozo:computePay() DolgPtr = &aUgynok; fizetes = DolgPtr -> computePay(); // Ugynok:computePay() DolgPtr = &aFonok; fizetes = DolgPtr -> computePay(); // Menedzser:computePay() 31
33
Virtuális tagfüggvények
Ha a computePay() függvény nem lenne virtuális, akkor mindegyik a Dolgozo: computePay()-t hívná meg. 32
34
Polimorfizmus Az a képesség, hogy egy objektumra vonatkozóan úgy tudunk tagfüggvényeket hívni, hogy az objektum pontos típusát nem ismerjük. 33
35
Dinamikus kötés Late binding Dynamic binding Fordítási időben nem képes meghatározni, hogy milyen függvényt hívunk. Futási időben rendeli hozzá. 34
36
Virtuális függvények implementálása
Nagyon hatékony. Gyorsan hívhatók (mint a normál függvények) Dinamikus kötés a C++-ban egy tábla (virtuális fv-ek táblája, vagy V-tábla) segítségével. Ez egy tömb, amelyet a compiler hoz létre minden osztály számára. (Függvény pointerek tömbje a virtuális függvények számára). 35
37
V tábla kezelése Egy osztály minden előfordulása tartalmaz egy pointert a V táblára. Amikor egy DolgPtr->computePay() utasítás végrehajtódik, akkor a DolgPtr által mutatott objektumban levő V-tábla pointer alapján megtalálja azt a fv-t, amelyet hívnia kell. 36
38
V-tábla 37
39
V-tábla 38
40
Absztrakt osztályok Pure virtual függvények
virtual float computePay() = 0; Ekkor nem kell definíció! Az az osztály, amely pure virtual függvényt definiál, absztrakt osztály. 39
41
Öröklődés Objektumok közötti speciális kapcsolat.
(Egy osztály a másik általánosításaként, vagy éppen specializált változataként jelenik meg.) Ember, diák, tanár.
42
Program készítése két módon:
IS_A reláció. Program készítése két módon: független osztály kialakítása öröklődéssel történő definíció alaposztály származtatott osztály
43
Újrafelhasználhatóság
Az öröklődéssel történő megoldás előnyei: hasonlóság kiaknázása miatt a program egyszerűbb - osztálykönyvtárak kialakítása, felhasználása (újrafelhasználhatóság).
44
Öröklődés leírása Ember név, kor Diák +átlag, évfolyam
általánosít Ember név, kor az egy az egy Diák +átlag, évfolyam Tanár +fizetés, tárgy specializál
45
Geometriai alakzatok példája
Shape hely, szín, Move() analitikus öröklés Rect +sarok, Draw() Line +vég, Draw() Circle +sugár, Draw() korlátozó öröklés Square
46
Alakzatok fajtái Általános alakzat: Shape. (szín, hely)
Speciális alakzatok: Rect, Line, Circle
47
Általános alakzat osztálya
class Shape { protected: int x, y, col; public: Shape ( int x0, int y0, int col0 ) { x = x0; y = y0; col = col0; } void SetColor ( int c ) { col = c; } };
48
Line osztály class Line : public Shape { // Line = Shape + ...
int xe, ye; public: Line( int x1, int y1, int x2, int y2, int c ) : Shape( x1, y1, c ) { xe = x2, ye = y2; } void Draw( ); void Move (int dx, int dy ) ; };
49
Line osztály Draw() metódusa
void Line :: Draw( ) { // cout << "\nLine: " << x << ',' << y; // cout << " : " << xe << ',' << ye << " ; " << col; _SetColor (col ) ; // rajz a grafikus könyvtárral _MoveTo ( x,y ); _LineTo (xe, ye ) ; }
50
Line osztály Move() metódusa
void Line :: Move( int dx, int dy ) { int cl = col; //tényleges rajzolási szín elmentése col = BGD; //rajzolási szín legyen a háttér színe Draw( ); // A nonal letörlése az eredeti helyről x += dx; y += dy; // mozgatás: a pozíció változik col = cl; // a rajzolási szín a tényleges szín Draw( ); // A vonal felrajzolása az új pozícióra
51
Rect osztály class Rect : public Shape { // Rect = Shape + ...
int xc, yc; public: Rect( int x1, int y1, int x2, int y2, Color c ) : Shape( x1, y1, c ) { xc = x2, yc = y2; } void Draw( ); void Move ( int dx, int dy ) ; };
52
Rect osztály Draw() metódusa
void Rect :: Draw( ) { cout << "\nRect: " << x << ',' << y; cout << " : " << xc << ',' << yc << " ; " << col; }
53
Származtatással kapcsolatos fogalmak
protected hozzáférés-módosító szó class Line :: public Shape {.....} származtatás, szülő (ős), gyermek (származtatott) public és private jelentése. Származtatott osztályban a tagfüggvényeket újradefiniálhatjuk (ez felülbírálja az alaposztály ugyanilyen nevű tagfüggvényét.
54
Konstruktorok meghívása
Line konstruktorának definíciója: Line( int x1, int y1, int x2, int y2, int c ) : Shape( x1, y1, c ) { xe = x2, ye = y2; } Definíció szerint az alaposztály konstruktora is meghívásra kerül.
55
Move függvény vizsgálata
Vizsgáljuk meg az egyes osztályokban lévő Move függvényt! Ugyanaz, csak mindegyik más Draw() függvényt hív meg. Virtuális tagfüggvény!
56
Move() elhelyezése az ősosztályban
class Shape { protected: int x, y, col; public: Shape( int x0, int y0, int col0 ) { x = x0; y = y0; col = col0; } void SetColor( int c ) { col = c; } void Move ( int dx, int dy ) ; virtual void Draw ( ) { } };
57
Move() megvalósítása void Shape :: Move( int dx, int dy ) {
int cl = col; //tényleges rajzolási szín elmentése col = BGD; //rajzolási szín legyen a háttér színe Draw( ); // A vonal letörlése az eredeti helyről x += dx; y += dy; // mozgatás: a pozíció változik col = cl; // a rajzolási szín a tényleges szín Draw( ); // A vonal felrajzolása az új pozícióra
58
Line osztály class Line : public Shape { // Line = Shape + ...
int xe, ye; public: Line( int x1, int y1, int x2, int y2, int c ) : Shape( x1, y1, c ) { xe = x2, ye = y2; } void Draw( ); };
59
Rect osztály class Rect : public Shape { // Rect = Shape + ...
class Rect : public Shape { // Rect = Shape + ... int xc, yc; public: Rect( int x1, int y1, int x2, int y2, Color c ) : Shape( x1, y1, c ) { xc = x2, yc = y2; } void Draw( ); };
60
Üzenetek objektumoknak
void main ( ) { Rect rect( 1, 10, 2, 40, RED ); Line line( 3, 6, 80, 40, BLUE ); Shape shape( 3, 4, GREEN ); shape.Move( 3, 4 ); // 2 db Draw hivás line.Draw( ); line.Move( 10, 10 ); // 2 db Draw hivás
61
Metódusok meghívása indirekten
Shape * sp[10]; sp[0] = ▭ sp[1] = &line; // nem kell cast for( int i = 0; i < 2; i++ ) sp[i] -> Draw( ); //indirekt Draw() }
62
Virtuális Shape::Draw Nem virtuális shape.Move() line.Draw() Line::Draw line.Move() sp[0] -> Draw(), mutatótípus Shape * de Line objektumra mutat sp[1] -> Draw(), de Rect objektumra mutat Rect::Draw
63
Szimuláció C programmal
struct Shape { int x, y, col }; //Shape adattagjai void Draw_Shape (struct Shape * this) {} //Shape::Draw
64
Move() szimulációja void Move_Shape (struct Shape * this, int dx, int dy) { //Shape::Move int cl = this ->col; //tényleges rajzolási szín elmentése this ->col = BGD; //rajzolási szín legyen a háttér színe Draw_Shape( this ); // A vonal letörlése az eredeti helyről this ->x += dx; this ->y += dy; // mozgatás: a pozíció változik this ->col = cl; // a rajzolási szín a tényleges szín Draw_Shape( this ); // A vonal felrajzolása az új pozícióra }
65
Tisztán virtuális tagfüggvény - absztrakt alaposztály.
class Shape { protected: int x, y, col; public: Shape( int x0, int y0, int col0 ) { x = x0; y = y0; col = col0; } void SetColor( int c ) { col = c; } void Move ( int dx, int dy ) ; virtual void Draw ( ) = 0; };
66
Virtuális függvények Tegyük fel, hogy van egy A alaposztályunk és egy B származtatott osztályunk, amelyben az alaposztály f függvényét újradefiniáltuk. class A { public: void f ( ); // A: :f }; class B : public A { void f ( ); // B: : f
67
Metódus kiválasztása Az objektum orientált programozás alapelve szerint egy üzenetre lefuttatott metódust a célobjektum típusa és az üzenet neve ( valamint az átadott paraméterek típusa ) alapján kell kiválasztani. Tehát, ha definiálunk egy A típusú a objektumot és egy B típusú b objektumot, és mindkét objektumnak f üzenetet küldünk, akkor azt várnánk el, hogy az a objektum esetében az A :: f, míg a b objektumra a B:: f tagfüggvény aktivizálódik. Vannak egyértelmű esetek, amikor ezt a kívánságunkat a C++ fordító program minden további nélkül teljesíteni tudja:
68
Objektumok definiálása
{ A a; B b; a. f ( ) ; // A : : f hívás b. f ( ) ; // B : : f hívás }
69
Direkt üzenet küldése Ebben a példában az a.f ( ) A típusú objektumnak szól, mert az a objektumot az A a; utasítással definiáltuk. Így a fordítónak nem okoz gondot, hogy ide az A:: f hívást helyettesítse be. A C++ nyelvben azonban vannak olyan lehetőségek is, amikor a fordító program nem tudja meghatározni a célobjektum típusát. Ezek a lehetőségek a részint az indirekt üzenetküldést, részint az objektumok által saját maguknak küldött üzeneteket foglalják magukban. Nézzük először az indirekt üzenetküldést:
70
Indirekt üzenet küldése
{ A a ; B b; A * pa ; if ( getchar ( ) = = 'i ' ) pa = & a ; else pa = & b; pa - > f ( ) ; // indirekt üzenetküldés }
71
Célobjektum meghatározása
Az indirekt üzenetküldés célobjektuma, attól függően, hogy a program felhasználója az i billentyűt nyomta-e le, lehet az A típusú a objektum vagy a B típusú b objektum. Ebben az esetben fordítási időben nyilván nem dönthető el a célobjektum típusa. Megoldásként két lehetőség kínálkozik:
72
Nem virtuális eset Kiindulva abból, hogy a pa mutatót A* típusúnak definiáltuk, jelentse ilyen esetben a pa -> f ( ) az A: : f tagfüggvény meghívását. Ez ugyan téves, ha a pa a b objektumot címzi meg, de ennél többre fordítási időben nincs lehetőségünk.
73
Virtuális eset 1Bízzuk valamilyen futási időben működő mechanizmusra annak felismerését, hogy pa ténylegesen milyen objektumra mutat, és ennek alapján futási időben válasszunk A : : f és B : : f tagfüggvények közül.
74
Két lehetőség a C++-ban
A C++ nyelv mindkét megoldást felkínálja, melyek közül aszerint választhatunk, hogy az f tagfüggvényt az alaposztályban normál tagfüggvénynek ( 1. lehetőség ), vagy virtuálisnál ( 2. lehetőség ) deklaráltuk.
75
Önmagának szóló üzenet
Hasonló a helyzet az "önmagukban beszélő" objektumok esetében is. Egészítsük ki az A osztályt egy g tagfüggvénnyel, amely meghívja az f tagfüggvényt. class A { public: void f ( ) ; // A : : f void g ( ) { f ( ) ; ) };
76
B osztályban f átdefiniálása
class B : public A { public: void f ( ) ; // B : : f } ;
77
A::f() vagy B::f() meghívása
A B típusú objektum változtatás nélkül örökli a g tagfüggvényt és újra definiálja az f-t. Ha most egy B típusú objektumnak küldenénk g üzenetet, akkor a saját magának, azaz az eredeti g üzenet célobjektumának küldene f üzenetet. Mivel az eredeti üzenet célja B típusú, az lenne természetes, ha ekkor a B::f hívódna meg. A tényleges célobjektum típusának felismerése azonban nyílván nem végezhető el fordítási időben. Tehát vagy lemondunk erről a szolgáltatásról és az f tagfüggvényt normálnak deklarálva a fordító a legkézenfekvőbb megoldást választja, miszerint a g törzsében mindig az A::f tagfüggvényt kell aktivizálni. Vagy pedig egy futási időben működő mechanizmusra bízzuk, hogy a g törzsében ismerje fel az objektum tényleges típusát és a meghívandó f-t ez alapján válassza ki.
78
Többszörös öröklődés (multiple inheritance)
Irodai alkalmazottakat kezelő probléma: Alkalmazottak (Employee) Menedzserek (Manager) Ideiglenes alkalmazottak (Temporary) Ideiglenes menedzserek (Temporary manager)
79
Osztályok
80
Employee osztály class Employee { protected: char name[20];
long salary; public: Employee (char *nm, long sl) ( strcpy( name,nm ) ; salary = sl ; } };
81
Manager osztály class Manager : public Employee { int level ; public:
Manager (char *nam, long sal, int lev) : Employee (nam, sal) ( level = lev; } } ;
82
Temporary osztály class Temporary : public Employee { int emp_time;
Temporary (char *nam, long sal, int time ); : Employee (nam, sal ) { emp_time = time} };
83
Temp_Man osztály class Temp_Man : public Manager, public Temporary {
Temp_Man (char *nam, long sal, int lev, int time) : Manager (nam, sal, lev), Temporary (nam, sal, time) {} };
84
Lehetséges elhelyezésük a memóriában
85
Nevek ütközése class A{ class B{ protected: protected: int x; int x;
}; }; class C: public A, public B { int f() { x=3; x=5;} };
86
Többértelműség megszüntetése
A többértelműség megszüntethető a scope operátor felhasználásával: int f() { { A::x=3; B::x=5;} Azonos nevű adattagok összevonása ellen szól a kompatibilitás elvesztése.
87
Megoldás: class Manager: virtual public Employee {…};
class Temporary: virtual public Employee {…}; class Temp_Man: virtual public Manager, public Temporary { public: Temp_Man ( char * nam, long sal, int lev, int ti,e) :Employee (nam, sal), MAneger (NULL, 0L, lev), Temporary (NULL, 0L, ti,e) { } };
88
Memóriában való elhelyezésük
89
A konstruktor feladatai
A virtuális alaposztályok konstruktorainak hívása, akkor is, ha a virtuális alaposztály nem közvetlen ős. A közvetlen, nem virtuális alaposztályok konstruktorainak hívása. A saját rész konstruálása A virtuálisan származtatott osztályok objektumaiban egy mutatót kell beállítani az alaposztály adattagjainak megfelelő részre. ha az objektumosztályban van olyan virtuális függvény, amely itt új értelmet nyer (azaz az osztály a virtuális függvényt újradefiniálja), akkor az annak megfelelő mutatókat a saját megvalósításra kell állítani. A tartalmazott objektumok konstruktorainak meghívása. A konstruktornak a programozó által megadott részei csak a fenti feladatok elvégzése után kerülnek végrehajtásra.
90
A destruktorok feladatai
A destruktor programozó által megadott részének a végrehajtása. A komponensek megszüntetése a destruktoraik hívásával. A közvetlen, nem-virtuális alaposztályok destruktorainak hívása. A virtuális alaposztályok destruktorainak hívása.
91
Függvénysablonok használata
Különböző függvények hasonló feldolgozás különböző adattípusok
92
Sablonok definíciója A sablonok egy utasításhalmazt definiálnak, amellyel programjaink később további függvényeket hozhatnak létre.
93
Sablonok használata két vagy több függvény gyors definiálására valók, melyek hasonló utasításokkal, de különböző paraméterekkel, vagy visszaadott értéktípussal dolgoznak.
94
Sablonok feldolgozása
A C++ fordító létrehozza a függvényeket a sablon nevére utaló prototípusokban megadott típusokkal.
95
max függvény sablonja template<class T> T max ( T a, T b) {
template<class T> T max ( T a, T b) { if (a > b ) return (a); else return (b); }
96
Sablonok tulajdonságai
A T a sablon általános típusa. Prototípusokat kell deklarálnunk az egyes típusokhoz: float max(float, float); int max (int, int)
97
Főprogram: { cout << "A 100 és 200 közül a nagyobb: "<< max (100, 200) << endl; cout << "Az és közül a nagyobb: " << max (5.123, 1.200) << endl; }
98
A teljes program #include <iostream.h>
template<class T> T max ( T a, T b) { if (a > b ) return (a); else return (b); } float max(float, float); int max (int, int);
99
A teljes program folytatása
void main() { cout << "A 100 ‚s 200 közül a nagyobb: "<< max (100, 200) << endl; cout << "Az ‚s 1.2 közül a nagyobb: "<< max (5.123, 1.2) << endl; }
100
Osztálysablonok használata
A template kulcsszó segítségével létrehozhatunk osztálysablonokat, amelyeket az osztálydefiníció használhat adattagok, és tagfüggvények visszaadott értékeinek valamint paraméterértékek típusainak megadására.
101
tomb osztály létrehozása
#include <iostream.h> #include <stdlib.h> class tomb { public: tomb (int meret); long osszeg ( void); int atlag_ertek(void); void tomb_kiiras(void); int ertek_hozzaadas(int); private: int *adatok; int meret; int index; };
102
Metódusok definiálása
tomb:: tomb(int meret) { adatok = new int [meret]; if (adatok == NULL) cerr <<"Keves a memoria -- a program befejezodik" << endl; exit(1); } tomb::meret = meret; tomb::index = 0;
103
Metódusok definiálása
long tomb::osszeg(void) { long osszeg = 0; int i; for (i=0; i<index; i++) osszeg += adatok[i]; return (osszeg); }
104
Metódusok definiálása
int tomb::atlag_ertek(void) { long osszeg = 0; int i; for (i=0; i<index; i++) osszeg += adatok[i]; return (osszeg/index); }
105
Metódusok definiálása
void tomb::tomb_kiiras(void) { int i; for (i=0; i<index; i++) cout<< adatok[i]<<' '; cout<< endl; }
106
Metódusok definiálása
int tomb::ertek_hozzaadas(int ertek) { if (index== meret) return(-1) else adatok[index] = ertek; index++; return(0); }
107
Főprogram void main(void) { tomb szamok(100); int i;
for(i = 0; i<50; i++) szamok.ertek_hozzaadas(); szamok.tomb_kiiras(); cout<<"A szamok osszege: "<<szamok.osszeg() <<endl; cout<<"Az atlagertek: "<<szamok.atlag_ertek() <<endl; }
108
Az előző feladat sablonnal
#include <iostream.h> #include <stdlib.h> template<class T, class T1> class tomb { public: tomb (int meret); T1 osszeg ( void); T atlag_ertek(void); void tomb_kiiras(void); int ertek_hozzaadas(T); private: T *adatok; int meret; int index; };
109
Metódusok definiálása
template<class T,class T1> tomb<T,T1>:: tomb(int meret) { adatok = new T [mret]; if (adatok == NULL) cerr <<"Keves a memoria -- a program befejezodik" << endl; exit(1); } tomb::meret = meret; tomb::index = 0;
110
Metódusok definiálása
template<class T,class T1> T1 tomb<T,T1>::osszeg(void) { T1 osszeg = 0; int i; for (i=0; i<index; i++) osszeg += adatok[i]; return (osszeg); }
111
Metódusok definiálása
template<class T,class T1> T tomb<T,T1>::atlag_ertek(void) { T1 osszeg = 0; int i; for (i=0; i<index; i++) osszeg += adatok[i]; return (osszeg/index); }
112
Metódusok definiálása
template<class T,class T1> void tomb<T,T1>::tomb_kiiras(void) { int i; for (i=0; i<index; i++) cout<< adatok[i]<<' '; cout<< endl; }
113
Metódusok definiálása
template<class T,class T1> int tomb<T,T1>::ertek_hozzaadas(T ertek) { if (index== meret) return(-1) else adatok[index] = ertek; index++; return(0); }
114
Főprogram void main(void) {
tomb<int, long> szamok(100); // 100 elemes tomb tomb<float, float> ertekek(200); // 200 elemes tomb int i; for(i = 0; i<50; i++) szamok.tomb_kiiras(); cout<<"A szamok osszege: "<<szamok.osszeg() <<endl; szamok.ertek_hozzaadas(i); cout<<"Az atlagertek: "<<szamok.atlag_ertek() <<endl;
115
Főprogram folytatása for(i = 0; i<100; i++)
for(i = 0; i<100; i++) ertekek.ertek_hozzaadas( i * 100); ertekek.tomb_kiiras(); cout<<"A szamok osszege: "<<ertekek.osszeg() <<endl; cout<<"Az atlagertek: "<<ertekek.atlag_ertek() <<endl; }
116
Osztálysablon létrehozásához
az osztálydefiníció elé tegyük a template kulcsszót és a típusszimbólumokat, például T és T1. Mindegyik osztályfüggvény definíciója elé ugyanezt a template utasítást kell tennünk. Ezenkívül osztály_ név < T, T1> :: függvény_nev
117
Objektumok létrehozása osztálysablonnal
sablon osztaly_nev< típus1, típus2> objektum_nev ( par1, par2) Például: tomb<char, int> kis_szamok(100)
118
Student osztály #include <iostream.h> #include <string.h>
enum BOOL { FALSE, TRUE } ; class Student { char name[30]; double average; public: Student (char *n =NULL, double a = 0.0 ) { strcpy(name,n); average = a;} double Average() { return average;} void Set (char *n, double a ) { strcpy(name,n);average = a;} char* GetNev(){return name;} double GetAtlag () {return average;} };
119
StudentListElem osztály
class StudentList; class StudentListElem { friend class StudentList; Student data; StudentListElem *next; public: StudentListElem (){} StudentListElem (Student d, StudentListElem *n) { data =d; next = n;} };
120
StudentList class StudentList { StudentListElem head, *current;
int Compare (Student& d1, Student& d2) {return (d1.Average() > d2.Average() ) ; } public: StudentList() { current = &head; head.next =0; } void Insert (Student&); BOOL Get (Student&); };
121
Metódusok definiálása
void StudentList :: Insert (Student& data) { for (StudentListElem* p =&head; p->next !=NULL; p=p->next) if (Compare (p-> data, data) ) break; StudentListElem* old = new StudentListElem ( p->data, p->next); p->data = data; p->next = old; }
122
Metódusok definiálása
BOOL StudentList:: Get (Student& e) { if(current->next == NULL ) { current = &head; return FALSE; } e = current ->data; current = current->next; return TRUE;
123
Főprogram main() { StudentList list; Student st; char nev[30];
double atlag; char cont; double average = 0; int nstudent = 0;
124
Főprogram folytatása do { cout << "\nName: "; cin >> nev;
cout << "\nAverage: "; cin >> atlag; st.Set(nev,atlag); list.Insert( st ); nstudent++; average += atlag; cout << "\nMore Students? (y/n)"; cin >> cont; } while ( cont == 'y' );
125
Főprogram folytatása average /= nstudent; while ( list.Get( st ) ) {
while ( list.Get( st ) ) { if (st.GetAtlag() >= average) cout << st.GetNev() << " " << st.GetAtlag() << "\n"; }
126
List osztály template-tel
#include <iostream.h> #include <process.h> enum BOOL { FALSE, TRUE }; // GENERIC LIST TYPE template<class R> class List;
127
ListElem template <class T> class ListElem {
friend class List<T>; T data; ListElem * next; public: ListElem( ) { } ListElem( T d, ListElem * n) { data = d; next = n; } };
128
List template <class R> class List {
ListElem<R> head, *read_ptr; public: List( ) { head.next = NULL; read_ptr = &head; } void Insert( R& data ); // insert into the list BOOL Get( R& data ); // get next from the list, ret==IsEND void Select( int index ); // select for the next Get virtual int Compare( R& d1, R& d2 ) { return 1; } };
129
Metódusok definiálása
template <class R> void List<R> :: Insert ( R& data ) { for( ListElem<R> *p = &head; p->next != NULL; p = p->next ) { if ( Compare( p->data, data) == 1 ) break; } ListElem<R> *old = new ListElem<R>( p->data, p->next); p->data = data; p->next = old;
130
Metódusok definiálása
template <class R> BOOL List<R> :: Get ( R& data ) { if ( read_ptr -> next == NULL ) { // end of list read_ptr = &head; return FALSE; } else { // not end, step to next data = read_ptr -> data; read_ptr = read_ptr -> next; return TRUE; }
131
Metódusok definiálása
/*template <class R> void List<R> :: Select ( int index ) { read_ptr = &head; if (index == 0) { if ( read_ptr->next == NULL) cerr << "Invalid Select in List"; }else { for( int i = 0; i < index; i++ ) { read_ptr = read_ptr->next; }
132
Student template-tel #include "templ11.cpp" struct Student {
#include "templ11.cpp" struct Student { char name[20]; int year; double average; };
133
Főprogram void main() { Student st; List<Student> list;
char cont; double average = 0; int nstudent = 0;
134
Főprogram folytatása do {
cout << "\nName: "; cin >> st.name; cout << "\nYear: "; cin >> st.year; cout << "\nAverage: ";cin>> st.average; list.Insert( st ); nstudent++; average += st.average; cout << "\nMore Students? (y/n)"; cin >> cont; } while ( cont == 'y' );
135
Főprogram folytatása average /= nstudent; while ( list.Get( st ) ) {
while ( list.Get( st ) ) { if (st.average >= average) cout << st.name << " " << st.average << "\n"; }
Hasonló előadás
© 2024 SlidePlayer.hu Inc.
All rights reserved.