Programozás C++ osztályok
Fodor Attila Pannon Egyetem Műszaki Informatikai Kar Villamosmérnöki és Információs Rendszerek Tanszék
[email protected]
2010. február 25.
C++ osztályok
Bevezetés
Osztályok
Objektum-orientáltság jellemzői Adatmodell és az eljárásmodell elválaszthatatlan Absztrakt eszköz és fogalomrendszer Újrafelhasználhatóság Valós világot nagyon megközelíti
Osztály (Class) Programozó által meghatározott típus
Fodor A. (Pannon Egyetem)
Programozás
2010. február 25.
2 / 35
C++ osztályok
Bevezetés
Eszközök a C nyelvben
Struktúra és függvények alkalmazása Adatok tárolása Struktúra alkalmazásával Az adattagok tárolják az adattagok tárolják
Adatok kezelése/feldolgozása Függvények segítségével Az adatokat tároló struktúrát át kell adni minden egyes függvénynek Az adatokat egyéb függvények is módosítani tudják A függvények és az adatok egymástól logikailag elkülönülnek
Fodor A. (Pannon Egyetem)
Programozás
2010. február 25.
3 / 35
C++ osztályok
Bevezetés
Példa - Julián dátum számítása Csillagászati számításoknál használt Julián-dátum az i.e. 4713. év első napjától eltelt napok számával és a óra/perc/másodperc helyett a nap decimális törtrészeivel adja meg az időpontokat JD kezdete i.e. 4712.01.01 óra 0 perc 0 másodperc UTC (Universal Time Coordinated)
Kialakulása Joseph Scaliger francia történész 1582-ben javasolta a feltehetően minden (akkor) ismert és megbízhatóan datált történelmi eseményt megelőző kezdetet a történelemtudomány számolási problémáinak kiküszöbölésére. (Például az időszámításunk kezdetének (az 1. év 1. nap délben) Julián-dátuma: 1 721 424,00 JD.) A csillagászatban a XIX. századtól terjedt el
Forrás és további részletek: Kulin György: A távcső világa (Gondolat Kiadó, 1980) Fodor A. (Pannon Egyetem)
Programozás
2010. február 25.
4 / 35
C++ osztályok
Bevezetés
Példa - Julián dátum számítása JD kiszámítása Az eltelt napok számát i.e. 4713. január 1-jétől i.sz. 1582. október 4-ig a Julianus-naptár napjainak száma adja 1582. október 15-től a Gergely-naptár napjainak száma A Julián naptár zavaros évei i.e. 45 - i. sz. 8.: amikor a szökőéveket nem szabályosan használták Kibővített i. e. 46-ot (445 napos évet) nem veszi figyelembe Szabályosan számolja a szökőévet (Például: szökőév az i.e. 1. - a.u.c. 753.(ab urbe condita = "a város alapításától fogva")) Az 1582. év 355 napos A többi szökőév szabályosan a két naptár szerinti szökőévektől függően 365, illetve 366
Az így kiszámított napok számának összegéből le kell vonni 0,5-öt, mert a Julián-nap kezdete déli 12 óra.
JD kiszámítása spec. esetektől eltekintve JD = 367Y − INT (7(Y + INT ((M + 9)/12))/4) − INT (3(INT ((Y + (M − 9)/7)/100) + 1)/4) + INT (275M/9) + D + 1721028.5 + UT /24 Fodor A. (Pannon Egyetem)
Programozás
2010. február 25.
5 / 35
C++ osztályok
Bevezetés
Eszközök a C nyelvben Példa Julian dátum számítása struct JDate { double jd; int sec, min, hour, day, month, year; }; void Init_JDate(JDate *d, int, int, int, int, int, int); void Add_Year(JDate *d, int n); void Add_Month(JDate *d, int n); void Add_Day(JDate *d, int n); void Add_Hour(JDate *d, int n); void Add_Min(JDate *d, int n); void Add_Sec(JDate *d, int n); double CalculateJD(JDate *d);
Fodor A. (Pannon Egyetem)
Programozás
2010. február 25.
6 / 35
C++ osztályok
Bevezetés
Függvények a C++ eszközeivel Struktúrába való tárolás Adattagokat Függvényeket
Példa struct JDate2 { double jd; int sec, min, hour, day, month, year;
void Init_JDate(int pyear, int pmonth, int pday, int phour, int pmin, in void Add_Year(int n); void Add_Month(int n); void Add_Day(int n); void Add_Hour(int n); void Add_Min(int n); void Add_Sec(int n); double CalculateJD(); };
Fodor A. (Pannon Egyetem)
Programozás
2010. február 25.
7 / 35
C++ osztályok
Bevezetés
Függvények implementálása a C++ eszközeivel Struktúrába való tárolás Adattagokat Függvényeket
Példa
void JDate2::Init_JDate(int pyear, int pmonth, int pday, int phour, int pmin { sec = psec; min = pmin; hour = phour; day = pday; month = pmonth; year = pyear; jd = CalculateJD(); } double JDate2::CalculateJD() { ... } Fodor A. (Pannon Egyetem)
Programozás
2010. február 25.
8 / 35
C++ osztályok
Osztályok
Osztály
Osztály (Class) Absztrakt eszköz Típusfogalom általánosítása (az eljárásorientált nyelveknél) Azonos attribútumú és módszerű objektumok együttese Osztályhoz köthetőek az objektumok Osztályból származtathatóak le az objektumok példányai
Létrehozása a C++ nyelvben class osztaly_neve { ... };
Fodor A. (Pannon Egyetem)
Programozás
2010. február 25.
9 / 35
C++ osztályok
Osztályok
Osztály Példa
void CDate::Init_JDate(int pyear, int pmonth, int pday, int phour, int pmin, { sec = psec; min = pmin; hour = phour; day = pday; month = pmonth; year = pyear; jd = CalculateJD(); } double CDate::CalculateJD() { //... }
Fodor A. (Pannon Egyetem)
Programozás
2010. február 25.
10 / 35
C++ osztályok
Elérhetőség
Elérhetőség szabályozása a C++ nyelvben Bezárás (Encapsulation) (OO ismétlés) Információrejtés elve (Information hiding) Interfész és implementációs rész Az osztály objektumaihoz csak az interfész részen keresztül férhetünk hozzá Az osztály implementációhoz nem lehet hozzáférni
Az attributumok két részre bonthatóak Nyilvános (public) rész minden kliens osztály lát Privát (private) rész kívülről nem látható
Ha az adattagokat kívülről valaki megváltoztatja, akkor hibásan működhetnek az osztályfüggvények ⇒ Nem megengedhető az adatok elérése osztályon kívülről Védeni kell ezekeket az adatokat, le kell tiltani a hozzáférést
Az osztály adatait az interface függvényeknek kell megváltoztatni ⇒ Meg kell engedni az interface függvények elérése osztályon kívülről Megfelelő ellenőrzés után módosítják az osztály adattagjait Fodor A. (Pannon Egyetem)
Programozás
2010. február 25.
11 / 35
C++ osztályok
Elérhetőség
Elérhetőség szabályozása a C++ nyelvben
Védett (private) tagok Osztályon kívülről nem érhető el Csak az osztályon belülről módosítható Megadása: private: ... osztálytagok deklarációja ...
Nyilvános (public) tagok Osztályon kívülről is érhető el Osztályon kívülről és belülről is módosítható Rossz változó érték esetén, hibás adat megadása bárhol lehet a programban! ⇒ Nehéz a hibák lokalizálása Megadása: public: ... osztálytagok deklarációja ...
Fodor A. (Pannon Egyetem)
Programozás
2010. február 25.
12 / 35
C++ osztályok
Elérhetőség
Elérhetőség szabályozása a C++ nyelvben Az első public cimke előtt megadott tagok private elérésűek lesznek Az első public cimke utána következő tagok public elérésűek Példa:
class CJDate { double jd; int sec, min, hour, day, month, year; public: void Init_JDate(int pyear, int pmonth, int pday, int phour, int pmin, in void Add_Year(int n); void Add_Month(int n); void Add_Day(int n); void Add_Hour(int n); void Add_Min(int n); void Add_Sec(int n); double CalculateJD(); };
Fodor A. (Pannon Egyetem)
Programozás
2010. február 25.
13 / 35
C++ osztályok
Elérhetőség
Elérhetőség szabályozása a C++ nyelvben
Private tagok elérési kívülről nem lehetséges A fordító a hibát már fordítási időben jelzi Példa: CJDate temp_jd; temp_jd.day = 5;
A fordítóprogram letiltja a hozzáférést Hibaüzenet (MS Visual C++) error C2248: ’CDate::day’ : cannot access private member declared in class ’CDate’
Fodor A. (Pannon Egyetem)
Programozás
2010. február 25.
14 / 35
C++ osztályok
Elérhetőség
Elérhetőség szabályozása a C++ nyelvben
Osztályon belül módosítható az összes private tag Kellő körültekintéssel kell eljárni a módosításoknál
void CJDate::Init_JDate(int pyear, int pmonth, int pday, int phour, in { sec = psec; min = pmin; hour = phour; day = pday; month = pmonth; year = pyear; jd = CalculateJD(); }
Fodor A. (Pannon Egyetem)
Programozás
2010. február 25.
15 / 35
C++ osztályok
Konstruktor (Constructor)
Konstruktor (Constructor) Osztály létrehozásakor lefutó függvény Felhasználás: Az osztály létrehozásakor az inicializálás lefuttatása Osztályváltozók kezdőértékének beállítása Adatok tárolásához dinamikus memória fefoglalása (heap-ből)
Előnyök: Nem felejti el a felhasználó (programozó) az inicializálást Az inicializálás csak egyszer fut le Lehetséges, hogy egyazon osztályt többféle képpen lehet inicializálni (más paraméterekkel) Osztály helyes használatához szükséges adatokat így mindenképpen átadásra kerülnek
A konstruktor neve megegyezik az osztály nevével class osztaly_neve { // ... osztaly_neve( parameterek... ); }; Fodor A. (Pannon Egyetem)
Programozás
2010. február 25.
16 / 35
C++ osztályok
Konstruktor (Constructor)
Konstruktor (Constructor) Konstruktornak paraméterek is adhatóak Ha a konstruktornak vannak paraméterei, akkor azokat hiánytalanul meg kell adni az osztály létrehozásakor Példa: class CJDate { double jd; int sec, min, hour, day, month, year; void CJDate(int pyear, int pmonth, int pday, int phour, int pmin, // ... }; CJDate today = CJDate(2010, 2, 24, 16, 30, 0); CJDate bday(1979, 2, 17, 11, 55, 0);
Példa: (Hibás konstruktor megadás)
CJDate jd2; // error C2512: ’CJDate’ : no appropriate default constructor availabl
CJDate jd3(2010, 2, 24); // error C2661: ’CJDate::CJDate’ : no overloaded function takes 3 argu Fodor A. (Pannon Egyetem)
Programozás
2010. február 25.
17 / 35
C++ osztályok
Konstruktor (Constructor)
Konstruktor (Constructor) Probléma: Lehetséges, hogy egyazon osztályt többféle képpen lehet inicializálni (másféle paraméterekkel) Megoldás: Szükség van többféle konstruktorra Nevük megegyezik, de a paramétereikben különbözőnek class osztaly_neve { // ... osztaly_neve( parameterlista1... ); osztaly_neve( parameterlista2... ); osztaly_neve( parameterlista3... ); };
Figyelni kell a paraméterek számára és típusára! Figyelni kell a konstruktorok "elburjánzására"!
Fodor A. (Pannon Egyetem)
Programozás
2010. február 25.
18 / 35
C++ osztályok
Konstruktor (Constructor)
Konstruktor (Constructor) Példa: Nem akarjuk az időt beállítani csak a dátumot A mai dátummal akarjuk inicializálni
class CJDate { double jd; int sec, min, hour, day, month, year; public: CJDate(double pjd); CJDate(int pyear, int pmonth, int pday, int phour, int pmin, int p CJDate(int pyear, int pmonth, int pday, int phour); CJDate(int pyear, int pmonth, int pday); CJDate(); };
A paraméterek száma és típusa nem egyeik meg Konstruktorok kezdenek "elszaporodni"
Fodor A. (Pannon Egyetem)
Programozás
2010. február 25.
19 / 35
C++ osztályok
Konstruktor (Constructor)
Konstruktor (Constructor) Példa:
CJDate::CJDate(int pyear, int pmonth, int pday, int phour, int pmin, int pse { sec = psec; min = pmin; hour = phour; day = pday; month = pmonth; year = pyear; jd = CalculateJD(); } CJDate(int pyear, int pmonth, int pday) { sec = 0; min = 0; hour = 0; day = pday; month = pmonth; year = pyear; jd = CalculateJD(); } Fodor A. (Pannon Egyetem)
Programozás
2010. február 25.
20 / 35
C++ osztályok
Konstruktor (Constructor)
Konstruktor (Constructor) Hibás konstruktor függvény megadás: Paraméterekben megegyeznek egymással Fordításkor jelzi a fordító!
class CJDate { // ... public: CJDate(int pyear, int pmonth, int pday, int phour, int pmin, int p CJDate(int pday, int pmonth, int pyear, int psec, int pmin, int ph // ... };
Hibaüzenet error C2535: ’CJDate::CJDate(int,int,int,int,int,int)’ : member function already defined or declared ..\progea_3.cpp(61): see declaration of ’CJDate::CJDate’
Figyelni kell a paraméterek számára és típusára! (Nem egyezhetnek meg) Fodor A. (Pannon Egyetem)
Programozás
2010. február 25.
21 / 35
C++ osztályok
Konstruktor (Constructor)
Alapértelmezett konstruktor A konstruktorok "elburjánzásának" a megakadályozására szolgál Ötlet: Ahol nincsen paraméter érték megadva, ott a programozó által megadott értéket helyettesítse be a fordító Így kiküszöbölhető felesleges konstruktor írás
Megadása: class osztaly_neve { // ... osztaly_neve( tipus par1=def_ertek, tipus par1=def_ertek, ... ); };
Példa: class CJDate { // ... public: CJDate(int pyear=0, int pmonth=0, int pday=0, int phour=100, int pmin=100, int psec=100); }; Fodor A. (Pannon Egyetem)
Programozás
2010. február 25.
22 / 35
C++ osztályok
Konstruktor (Constructor)
Alapértelmezett konstruktor Példa (Konstruktor implementációja): class CJDate { // ... public: CJDate(int pyear=0, int pmonth=0, int pday=0, int phour=100, int pmin=100, int psec=100); }; CJDate::CJDate(int pyear, int pmonth, int pday, int phour, int pmin, int psec) { sec = psec!=100?psec:today.sec; //today globális változó min = pmin!=100?pmin:today.min; hour = phour!=100?phour:today.hour; day = pday?pday:today.day; month = pmonth?pmonth:today.month; year = pyear?pyear:today.year; jd = CalculateJD(); }
Fodor A. (Pannon Egyetem)
Programozás
2010. február 25.
23 / 35
C++ osztályok
Konstruktor (Constructor)
Alapértelmezett konstruktor Az alapértelmezett konstruktor mellett figyekni kell, hogy milyen konstruktor marad(hat) Figyelni kell a paraméterek számára és típusára! Példa: class CJDate { // ... public: CJDate(int int CJDate(int CJDate(int CJDate(); // ... };
pyear=0, int pmonth=0, int pday=0, phour=100, int pmin=100, int psec=100); pyear, int pmonth, int pday, int phour); pyear, int pmonth, int pday);
Hiba lesz a fordításnál
Fodor A. (Pannon Egyetem)
Programozás
2010. február 25.
24 / 35
C++ osztályok
Statikus tagok
Statikus tagok Probléma: Globális változók használata gondot okozhat Bárki módosíthatja A felhasználó (programozó) nem állítja be megfelelően az értékét
Megoldás: Globális változó(k) megszüntetése Statikus adattagok alkalmazása
Statikus adattagok mindig az osztályhoz tartoznak Statikus adattagok minig csak 1 példányban léteznek, ellentétben a többi adattaggal Statikus függvények: osztálytagokhoz hozzáférnek, de nem feltétlenül kell objektum(ok)ra meghívni
Fodor A. (Pannon Egyetem)
Programozás
2010. február 25.
25 / 35
C++ osztályok
Statikus tagok
Statikus tagok Példa: Osztály létrehozása
class CJDate { private: double jd; int sec, min, hour, day, month, year; static CJDate DefaultJD; public: CJDate(double pjd); CJDate(int pyear=0, int pmonth=0, int pday=0, int phour=100, int pmin=10 static SetDefaultJD(double pJD); // ... }; CJDate::SetDefaultJD(double pJD) { CJDate::DefaultJD = CJDate(pJD); }
Fodor A. (Pannon Egyetem)
Programozás
2010. február 25.
26 / 35
C++ osztályok
Statikus tagok
Statikus tagok
Példa (folytatás): Statikus tagok definiálása
CJDate::CJDate(int pyear, int pmonth, int pday, int phour, int pmin, int pse { sec = psec!=100?psec:DefaultJD.sec; min = pmin!=100?pmin:DefaultJD.min; hour = phour!=100?phour:DefaultJD.hour; day = pday?pday:DefaultJD.day; month = pmonth?pmonth:DefaultJD.month; year = pyear?pyear:DefaultJD.year; jd = CalculateJD(); } CJDate::SetDefaultJD(2455251.50000);
Fodor A. (Pannon Egyetem)
Programozás
//2010 Februar 24 00:00:00.0 UT
2010. február 25.
27 / 35
C++ osztályok
Osztály típusú objektumok másolása
Osztály típusú objektumok másolása
Szabadon másolhatóak Kezdőértékként egy azonos típusú osztály egy objektumának másolatát is kaphatják Példa: CJDate CJDate CJDate temp =
today = CJDate(2010, 2, 24, 16, 30, 0); bday(1979, 2, 17, 11, 55, 0); temp; today;
Fodor A. (Pannon Egyetem)
Programozás
2010. február 25.
28 / 35
C++ osztályok
Konstans függvények
Konstans függvények
Probléma: Védeni kell a tagváltozók értékeit a módosítástól A tagváltozók értékeihez nem lehet kiolvasni, mivel private elérésűek
A konstans függvények nem változtathatják meg a tagváltozók értékeit A változtatási kisérletre a fordítóprogram hibával leáll. Megadása: viszzat_ertek fv_neve(parameterek) const
Fodor A. (Pannon Egyetem)
Programozás
2010. február 25.
29 / 35
C++ osztályok
Konstans függvények
Konstans függvények Példa: class CJDate { double jd; int sec, min, hour, day, month, year; static CJDate DefaultJD; public: int GetYear() const {return year;} int GetMonth() const {return month;} int GetDay() const {return day;} double GetJD() const; // .. }; double CJDate::GetJD() const { return JD; }
Fodor A. (Pannon Egyetem)
Programozás
2010. február 25.
30 / 35
C++ osztályok
Konstans függvények
Mutable minősítő
Gyorsítótárba kerülő adatoknál használható class CJDate { double jd; mutable bool DateValid; mutable string StrDate; int sec, min, hour, day, month, year; static CJDate DefaultJD; // .. };
Fodor A. (Pannon Egyetem)
Programozás
2010. február 25.
31 / 35
C++ osztályok
Konstans függvények
Önhivatkozás Frissítő függvények egy referenciát adnak vissza önmagukra "Láncba" lehet fűzni a frissítő függvényeket Példa: class CJDate { // ... CJDate& SetYear(int); CJDate& SetMonth(int); CJDate& SetDay(int); void SetJD(CJDate& pJD) // ... }; void CJDate::SetJD(CJDate& pJD) { // ... pJD.SetYear(2010).SetMonth(2).SetDay(24); // ... } Fodor A. (Pannon Egyetem)
Programozás
2010. február 25.
32 / 35
C++ osztályok
Konstans függvények
Önhivatkozás Példa: void CJDate::SetJD(CJDate& pJD) { // ... pJD.SetYear(2010).SetMonth(2).SetDay(24); // ... } CJDate& CJDate::SetYear(int pYear); { // ... Year = pYear; jd = CalculateJD(); // ... return *this; }
*this az az objektumot, amelyre a tagfüggvényt meghívták
Fodor A. (Pannon Egyetem)
Programozás
2010. február 25.
33 / 35
C++ osztályok
Konstans függvények
Struktúrák és osztályok A struktúra (struct), olyan osztály, melynek tagjai alapértelmezés szerint nyilvánosak struct s { // ... } class s { public: // ... }
Elérhetőségi minősítés a struktúrába is rakható Osztályfüggvények is rakhatóak a struktúrába
Fodor A. (Pannon Egyetem)
Programozás
2010. február 25.
34 / 35
C++ osztályok
Konstans függvények
Osztályon belüli függvények Inline tagfüggvény Az osztályon belül definiált (nem csak deklarált) függvények helyben kifejtett függvény Kicsi, gyakran használt függvényeknél jó
Példa: class CJDate { double jd; int sec, min, hour, day, month, year; static CJDate DefaultJD; public: int GetYear() const {return year;} int GetMonth() const {return month;} int GetDay() const {return day;} double GetJD() const; // .. }; inline double CJDate::GetJD() const { return JD; }
Fodor A. (Pannon Egyetem)
Programozás
2010. február 25.
35 / 35