Get Even More Visitors To Your Blog, Upgrade To A Business Listing >>

Öröklés


      Az öröklés egy kód-újrahasznosítási módszer, ahol az új osztályok a már
megírt osztályok alapján készülnek felhasználván azok tulajdonságait és
algoritmusait, átírván némely algoritmust és létrehozván pár új tulajdonságot
és algoritmust. Nem csak kódot, de időt is takarít meg, mert a már létező
osztályokat nem kell újra tesztelni. Adatokat és tagfüggvényeket örökölni egy
vagy több osztálytól is lehet. Mindhárom adattípust (
public, private,
protected
) lehet örökölni, de
legtöbbször a publikus öröklést használjuk. Ebben az esetben ugyanis a derivált
(örökölt) osztály objektumai bárhol használhatók az ősosztály objektumaiként
is. A fordított eset viszont nem igaz, azaz az ősosztály objektumai nem
objektumai a derivált osztálynak is. Tulajdonképpen ez a legalapvetőbb
különbség az osztályok kombinálása (amikor más osztályok objektumait használjuk
tagváltozóként) és az öröklés között. A derivált osztály objektumai az
ősosztály objektumaiként is kezelhetőek. Az angolban ezt „is a” (öröklés) és „has a” (kombináció) típusú osztály kapcsolatként emlegetik. Akár egy külső
függvény, a derivált osztály sem fér hozzá az ősosztályának privát tagjaihoz,
hacsak nincsenek ehhez hozzáférést nyújtó publikus vagy protected tagfüggvények
az ősosztályban. Az öröklés egyik fölösleges tulajdonsága, hogy örökölnek a nem
használt publikus tagfüggvények is. Ha az ősosztály valamely tagfüggvényének
működése nem felel meg a derivált osztálynak, akkor azt újra lehet deklarálni a
derivált osztályban. Az ősosztály friend függvényei nem öröklődnek. Az öröklésre
példa az
Absztrakció című bejegyzésben található.





1. Mutató típusú objektumok átalakítása az osztályok között


2. Tagfüggvények használata


3. A public, protected és private típusú tagok öröklődése


4. A derivált osztályok konstruktorai és a destruktorai


5. A „uses a” és a „knows a” típusú kapcsolat


6. A többszörös öröklés









1. Mutató típusú
objektumok átalakítása az osztályok között


     
A mutató típusú objektumokat az ősosztály és a derivált osztály között
cast-tal lehet átalakítani vigyázva, hogy a
mutató és az új objektum típusa találjon.





point.h


#ifndef POINT_H


#define POINT_H


#include


using std::ostream;





class Point


{


     friend ostream& operatorconst Point&);





     public:


           Point(int = 0, int = 0); //konstruktor és a parametér hiányában fellépő értékek


           void setPoint(int, int); //Beállítja x és y protected tagváltozókat


           int getX() const { return x; }


           int getY() const { return y; }


     protected:                     //csak a derivált osztály érheti el


           int x, y; //egy pont koordinátái


};


#endif





point.cpp


#include


#include "point.h"





//konstruktor - beállítja a
tagváltozókat


Point::Point(int
a, int b)


{


     setPoint(a,
b);


}





// a tagváltozók beállítása


void Point::setPoint(int
a, int b)


{


     x =
a;


     y =
b;


}





// Kiírja az objektumot egyéni
formában


ostream& operatoroutput, const Point& p)


{


     output
'['
", " ']';


    


     return output; //fűzér mód


}





circle.h


#ifndef CIRCLE_H


#define CIRCLE_H


#include


using std::ostream;


#include


using std::ios;


using std::setiosflags;


using std::setprecision;


#include "point.h"





class Circle : public
Point //A Point publikus deriváltja


{


     friend ostream& operatorconst Circle&);





     public:


           Circle(double r = 0.0, int x
= 0, int y = 0);


           void setRadius(double);


           double getRadius() const;


           double area() const;


          


     protected:


           double radius;


};


#endif





circle.cpp


#include "circle.h"





// Előbb a Point konstruktorát hívja meg


Circle::Circle(double
r, int a, int
b) : Point(a, b)


{


     setRadius(r);
// és csak utána állítja be a saját tagváltozóit


}





void Circle::setRadius(double
r)


{


     radius
= (r > 0 ? r : 0); //a sugár csak pozitív lehet


}





double Circle::getRadius() const


{


     return radius;


}





double Circle::area() const


{


     return 3.14159 * radius * radius;


}





// Kiírja az objektumot egyéni
formában: Központ = [x, y]; Sugár = #.##


ostream& operatoroutput, const Circle& c)


{


     output
"Központ = "
static_cast(c)";";


     output
"Sugár = "
setiosflags(ios::fixed | ios::showpoint)


                                 


     return output;


}





test_point_circle.cpp


#include


using std::cout;


using std::endl;


#include


#include "circle.h"





int main()


{


     Point
*pointPtr = 0, p(30, 50);


     Circle
*circlePtr = 0, c(2.7, 120, 89);





     cout
"A p pont: "


     cout
"A c kör: "


    


     //a Circle objektum címét egy Point típusó mutatóba írja


     pointPtr
= &c; //upcasting


     cout
"\nA c kör a Point osztály
szemszögébôl: "


    


     //A Circle mutató felveszi a Point mutató értékét, ami
Circle objektumra mutat


     circlePtr
= static_cast(pointPtr); //downcasting


     cout
"\nA c kör a Circle osztály
szemszögébôl:\n"


    


     //területszámítás


     cout
"A c kör területe:
circlePtr->area() = "
area() endl;


    


     //a Point objektum címét egy Point típusó mutatóba írjuk


     pointPtr
= &p;


     //A
Circle mutató felveszi a Point mutató értékét, ami Point objektumra mutat


     circlePtr
= static_cast(pointPtr);


     cout
"\nA p pont a Circle osztály
szemszögébôl:\n"


    


     //teruletszámítás


     cout
"A c kör területe:
circlePtr->area() = "
area() endl;


    


     return 0;


}


A kimenet:


A p pont: [30,
50]


A c kör: Központ
= [120, 89];Sugár = 2.70





A c kör a Point
osztály szemszögébôl: [120, 89]





A c kor a Circle
osztály szemszögébôl:


Központ = [120,
89];Sugár = 2.70


A c kör
területe: circlePtr->area() = 22.90





A p pont a
Circle osztály szemszögébôl:


Központ = [30,
50];Sugár = 0.00


A c kör
területe: circlePtr->area() = 0.00





A Point ősosztály publikus interfésze tartalmazza a setPoint, getX és getY tagfüggvényeket. Az x és y tagváltozók viszont protected típusúak, hogy az osztály közvetlen felhasználói ne férjenek hozzá, de a
derivált osztályok igen. Ha
private típusúak lennének, akkor a derivált osztály is csak a Point publikus függvényeivel érhetné el. A Circle osztály a Point ősosztály publikus deriváltja: class Circle : public Point. Ez azt jelenti, hogy a Point
minden
public és protected tagja átöröklődött a Circle osztályba. Azt is jelenti, hogy a Circle publikus interfésze nem csak az area, setRadius és getRadius tagfüggvényekből áll, hanem magába foglalja a Point ősosztály publikus tagfüggvényeit is. Az
öröklésnél fontos, hogy a konstruktorok a megfelelő sorrendben hívódjanak meg.
Előbb az ős és utána az utód tagváltozóit kell inicializálni. Legegyszerűbb a
paraméterlista után kettősponttal jelezni, hogy a paraméterek közül melyek
inicializálják a Pointer osztály tagváltozóit:
Circle::Circle(double
r, int a, int
b) : Point(a, b)
. Ebben az
esetben az
a és a b lesz amit a Point konstruktor megkap. Ha ezt nem írjuk oda,
akkor is a Point konstruktor fut le hamarább, csakhogy az inicializált értékekkel,
melyek ebben az esetben nullák:
Point(int = 0, int = 0) . Ha ez az inicializálás sincs megírva, akkor a fordító hibát jelez. A Point *pointPtr = 0, p(30,
50);
programkód létrehoz egy NULL
mutatót és egy
p objektumot. Ugyanígy
készül a
Circle objektum is.
Mindét osztálynak van egy operátorfüggvénye, ami túlterheli a
operátort és saját stílusban írja ki az
objektumokat. A
Circle
derivált osztály használhatja a
Point
ősosztály operátorfüggvényét is, ám az csak a saját maga által ismert adatokat
tudja kiírni. Hogy a
Point
operátorfüggvénye hívódjon meg,
Point
típusú mutatót kell kiíratni, tehát a
pointPtr fel kell vegye a Circle típusú objektum címét. A pointPtr = &c; műveletet upcasting-nak nevezik, mert a
derivált objektumot kezeljük ősobjektumként. Ez azt jelenti, hogy csak azok az
adatok elérhetőek az objektumból amelyek az ősosztályból valók, ebben az
esetben az
x és y koordináta. Ennek ellenkezője a
downcasting:
circlePtr
= static_cast(pointPtr);
. Az upcasting esetén a Circle objektum mutatója Point típusú lett. A downcasting esetén visszaalakítás
történik, melyben az értéket csakis egy
Circle
típusú mutató veheti fel. A program végül megadja a
Point objektum címét a pointPtr mutatónak, majd átalakítja Circle mutatóvá. Ennek eredménye, hogy kiíráskor
a
Circle operátorfüggvénye fog meghívódni és nem
fogja tudni, hogy mennyi a
Point
objektum területe és sugara, ezért az inicializált nullákkal helyettesíti az
ismeretlen adatokat.





     
Annak ellenére, hogy a derivált objektum az ősosztályból származik,
típusa mégis különbözhet. A publikus öröklés esetén a derivált objektumokat
lehet ősi objektumként kezelni, hiszen a tagok hozzáférési típusa nem változik.
Az öröklés célja, hogy az alaptulajdonságok mellett új tulajdonságokat
soroljunk fel, ezért a derivált osztály mindig több taggal rendelkezik mint az
ősosztály. Az ősosztályban ezért is nem lehet a derivált objektumokra
hivatkozni, mert az ismeretlen tagok definiálatlanul maradnának. A publikus
öröklés lehetővé teszi, hogy a derivált osztály mutatója átalakítható legyen,
hogy az ősosztály objektumára mutasson, ahogyan ezt a fenti példában láttuk. Tulajdonképpen
négyféleképp kombinálhatóak a mutatók és az objektumok a derivált és az
ősosztály között:


1. Az
ősobjektumra való hivatkozás egy ősmutató segítségével


pointPtr = &p;


      2. A
derivált objektumra való hivatkozás egy derivált mutató segítségével


circlePtr = &c;


      3. A
derivált objektumra való hivatkozás egy ősmutató segítségével. Ez lehetséges,
hiszen a derivált objektum az ősosztály objektuma is, viszont csak az ősosztály
tagjait használhatjuk, különben a fordító hibát jelez.


     pointPtr = &c;


4. Az
ősobjektumra való hivatkozás egy derivált mutató segítségével. Közvetlenül nem
lehet, csak ha átalakítjuk a derivált mutatót ősmutatóvá.


     circlePtr
= static_cast(pointPtr);









2. Tagfüggvények
használata


     
A derivált és az ősosztályok tagfüggvényei között olykor csak kevés
eltérés van, mint például az előző példában szereplő operátorfüggvények esetén.
Ilyenkor nem érdemes a függvény nevét megváltoztatni, ugyanis felülírható az
ősosztály tagfüggvénye. Egyszerűen újra kell deklarálni az adott függvényt a
derivált osztályba, és onnantól az lesz az elsődlegesen érvényes függvény.
Továbbra is használható marad az ősosztály tagfüggvénye, ám használni kell a
tartományoperátort.





employee.h


#ifndef EMPLOYEE_H


#define EMPLOYEE_H





class Employee


{


     public:


           Employee(const char*, const char*);


           void print() const// Kiírja a vezeték- és keresztnevet


           ~Employee();


     private:


           char* firstName;//dinamikusan
lefoglalt string


           char* lastName; //dinamikusan
lefoglalt string


};





#endif





employee.cpp


#include


using std::cout;


#include


#include


#include "employee.h"





Employee::Employee(const
char* first, const
char* last)


{


     firstName
= new char[strlen(first)
+ 1]; // dinamikus memórialefoglalás


     assert(firstName
!= 0);                  //
abort ha nem sikerül lefoglalni


     strcpy(firstName,
first);                //
bemásolja a bejövő paramétert a tagváltozóba





     lastName
= new char[strlen(last)
+ 1];


     assert(lastName
!= 0);


     strcpy(lastName,
last);


}





void Employee::print() const


{


     cout
' '
lastName;


}





Employee::~Employee()


{


     delete[] firstName; //memória
felszabaditás


     delete[] lastName; 
//memória felszabaditás


}





hourly.h


#ifndef HOURLY_H


#define HOURLY_H




This post first appeared on Altair Gate - News, please read the originial post: here

Share the post

Öröklés

×

Subscribe to Altair Gate - News

Get updates delivered right to your inbox!

Thank you for your subscription

×