Az előadás letöltése folymat van. Kérjük, várjon

Az előadás letöltése folymat van. Kérjük, várjon

Öröklődés Objektumok közötti speciális kapcsolat.

Hasonló előadás


Az előadások a következő témára: "Öröklődés Objektumok közötti speciális kapcsolat."— Előadás másolata:

1 Ö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.

2 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

3 Ú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).

4 Ö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

5 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

6 Alakzatok fajtái Általános alakzat: Shape. (szín, hely)
Speciális alakzatok: Rect, Line, Circle

7 Á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; } };

8 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 ) ; };

9 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 ) ; }

10 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

11 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 ) ; };

12 Rect osztály Draw() metódusa
void Rect :: Draw( ) { cout << "\nRect: " << x << ',' << y; cout << " : " << xc << ',' << yc << " ; " << col; }

13 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.

14 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.

15 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!

16 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 ( ) { } };

17 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

18 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( ); };

19 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( ); };

20 Ü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

21 Metódusok meghívása indirekten
Shape * sp[10]; sp[0] = &rect; sp[1] = &line; // nem kell cast for( int i = 0; i < 2; i++ ) sp[i] -> Draw( ); //indirekt Draw() }

22 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

23 Szimuláció C programmal
struct Shape { int x, y, col }; //Shape adattagjai void Draw_Shape (struct Shape * this) {} //Shape::Draw

24 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 }

25 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; };

26 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

27 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:

28 Objektumok definiálása
{ A a; B b; a. f ( ) ; // A : : f hívás b. f ( ) ; // B : : f hívás }

29 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:

30 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 }

31 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:

32 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.

33 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.

34 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. 

35 Ö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 ( ) ; ) };

36 B osztályban f átdefiniálása
class B : public A { public: void f ( ) ; // B : : f } ;

37 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.

38 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)

39 Osztályok

40 Employee osztály class Employee { protected: char name[20];
long salary; public: Employee (char *nm, long sl) ( strcpy( name,nm ) ; salary = sl ; } };

41 Manager osztály class Manager : public Employee { int level ; public:
Manager (char *nam, long sal, int lev) : Employee (nam, sal) ( level = lev; } } ;

42 Temporary osztály class Temporary : public Employee { int emp_time;
Temporary (char *nam, long sal, int time ); : Employee (nam, sal ) { emp_time = time} };

43 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) {} };

44 Lehetséges elhelyezésük a memóriában

45 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;} }; 

46 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.

47 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) { } };

48 Memóriában való elhelyezésük

49 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.

50 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.


Letölteni ppt "Öröklődés Objektumok közötti speciális kapcsolat."

Hasonló előadás


Google Hirdetések