0 Az objektum-orientáltság 0.1 Objektum fogalma Egy rendszer egyedileg azonosítható szereplője adatokkal és működéssel. Egységbezárás (encapsulation) - viselkedés a külvilág felé - belső struktúra (kívülről nem látható) kívülről nem látszik - állapot (kívülről nem látható) - adatok és kezelő függvények (szabályozható láthatóság kívülről) (data hiding) 0.2 Osztályok és példányok Megegyező szerkezetű, hasonló viselkedésű elemek mintája Osztály (class) Ez egy felhasználó által definiált típus (absztrakció) Az osztályhoz tartozó példány (instance) az objektum megkülönböztethetők ismerik saját osztályukat UML (Unified Modelling Language) Osztály: Példányok: Név (txt): Kutya Fajta (txt): Kor (int): Beoltják() Rex Eb1 Német juhász 3 Blöki 0.2.1 Operátorok túlterhelése (műveletek definiálhatók felhaszn. típusokra) Eb2 1
0.3 Osztály hierarchiák Öröklődés (inheritance) Állat ISA - Kompatibilitás Állat Tranzitív Madár Emlős Vizi állat Emlős Vereb Sas Bodri Kutya Rex Cet Ponty Kutya Bodri 0.3.1 Polimorfizmus Ugyanaz a metódus más- és másképpen működik a családfa szintjein - korai és késői kötés Síklap virtual Kerület virtual Terület Többszörös öröklődés (multiple inheritance) Körlap sugár Kerület Terület Gyűrű belső sugár Kerület Terület 0.4 Általánosított osztályok (azonos működés különböző típusokra) 0.5 STL (szabványos tárolók, bejárások, algoritmusok) 2
I. Osztályok fogalma Felhasználói (elvont) típus = adatszerkezet + tagfüggvények I.1 Struktúrák (deklaráció bárhol, ahol deklaráció lehet) struct nev { tipus1 adattag1; // alaphelyzetben a tagok kívülről láthatók tipus2 adattag2; típus4 tagfüggvény1(paraméterek){ return x void tagfüggvény2(paraméterek){ ; // kell a végén a pontosvessző I.1.1 Struktúra tagok elérése Statikus és referencia példány esetén Dinamikus példány esetén struct sember { string nev; int kor; ; // statikus struktúra sember jani; cout<<"jani neve:"; cin>>jani.nev; cout<<" "<<jani.nev<<endl; cout<<"jani kora:"; cin>>jani.kor; cout<<" "<<jani.kor<<endl; sember & clone =jani; I.1.2 Struktúra tagok kezdőértékei sember laci={"laci", 12; statpld.tag dinpld->tag // dinamikus struktúra sember * geza = new sember; cout<<"geza neve:"; cin>>geza->nev; cout<<" "<<geza->nev<<endl; cout<<"geza kora:"; cin>>geza->kor; cout<<" "<<geza->kor<<endl; delete geza; // dinamikust így is lehet sember * geza2 = new sember(); 3 sember * geza3 = geza2; //csak pointer másolás
I.2 Osztályok : csak default elérésben mások, mint a struktúrák Adattagok, függvények elérésének szabályozása - public private alapérték a private. A public publikussá tesz a következő intézkedésig, a struktúratagok elérhetősége is változtatható class nev { tipus1 tag1; tipus2 tag2; tipus3 tag3; ; // kell a végén a pontosvessző Az osztályokból képezett példányok az objektumok I.2.1 Osztálytagok elérése class cember { int szemelyi_szám; string nev; int kor; ; // rejtett adatelérési hiba egy statikus objektum példánynál cember geza; cout<<"geza neve:"; cin>>geza.nev; cout<<"geza szemelyiszama:";! cin>>geza.szemelyi_szám;! error C2039: 'szemelyi_szám' : is not a member of 'cember' (!) cout<<" "<<geza.nev<<endl; cout<<"geza kora:"; cin>> geza.kor; cout<<" "<<geza.kor<<endl; 4
I.2.2 Tagfüggvények Az adattípussal kapcsolatban álló (az adattagokon működő) fv-k belül, vagy kívül definiáltak. Lehetnek inline függvények (javaslat: befordít a hívás helyébe). A fejálományba csak egyszer. I.2.2.1 A láthatatlan this paraméter (a példányra mutató pointer, önhívatkozás ) return * this ref fv tip esetén az obj, érték esetén másolat az obj-ról return this obj-ra mutató pointer // Header.h #ifndef PL_H // csak egyszer #define PL_H #include <conio.h> #include <iostream> #include <iomanip> #include <string> using namespace std; struct sember { string nev; int kor; ; class cember { int szemelyi_szám; string nev; int kor; void oregszik(int evet); // kivül kifejtett C++ void ffi(){ this->szemelyi_szám = 1; // belül def. hozzáfér a this-hez inline void no() { szemelyi_szám = 2; // belül def. Hozzáfér, inline void nem(); // kivül kifejtett inline lesz; ; inline void cember::nem(){if (szemelyi_szám==1) cout <<"ffi"; else 5 cout <<"no"; cout <<endl; //inline
// Header.cpp #include "stdafx.h" #include "Header.h" void cember::oregszik(int evet) {// kívül definiált kor += evet; // objects.cpp #include "stdafx.h" #include "Header.h" int _tmain(int argc, _TCHAR* argv[]) { cember ervin; ervin.nev = "Ervin"; ervin.kor = 26; cout << "ervin neve:"; cout << " " << ervin.nev << endl; cout << "ervin kora:"; cout << " " << ervin.kor << endl; ervin.ffi(); // hozzáfér a személyi számhoz javít ervin.nem(); //hívás helyére befordítja a függvény utasításait ervin.no(); //hívás helyére befordítja a függvény utasításait ervin.nem(); //hívás helyére befordítja a függvény utasításait _getch(); return 0; 6
// objects.cpp #include "stdafx.h" #include "Header.h" int _tmain(int argc, _TCHAR* argv[]) { cember ervin; ervin.nev = "Ervin"; ervin.kor = 26; cout << "ervin neve:"; cout << " " << ervin.nev << endl; cout << "ervin kora:"; return 0; cout << " " << ervin.kor << endl; ervin.ffi();// hozzáfér a személyi számhoz javít ervin.no(); //hívás helyére befordítja a függvény utasításait ervin.nem(); //hívás helyére befordítja a függvény utasításait _getch(); 7
I.2.2.2 Konstans tagfüggvények és mutable minősítő A const tagfüggvények nem változtatják az adattagokat class valami { típus1 fvnév1(paraméterek) const { // megadás mutable tipus4 tag; A mutable kivételt képez // Header.h class cember { int szemelyi_szám; string nev; mutable int kor; void oregszik(int evet); void ffi(){ this->szemelyi_szám = 1; // belül def. hozzáfér a this-hez inline void no(){ szemelyi_szám = 2; // inline void nem(); int hany_eves_lesz() const { return ++kor; ; inline void cember::nem(){ if (szemelyi_szám == 1) cout << "ffi"; else cout << "no"; cout << endl; //inline // objects.cpp cout << "Ervin " << ervin.hany_eves_lesz() << " eves lesz" << endl; 8
I.2.2.3 Elérési függvények a privát adatokhoz szokás set_ get_ függvényekkel kezelni a rejtett tagokat (R/O) class dpoint { double x; double y; mutable int szamlal; void init(double x=0, double y=0) { this->x=x; this->y=y; szamlal=0; void set_x( double x) { this->x=x; szamlal=0; void set_y( double y) { this->y=y; szamlal=0; double get_x() const { szamlal++; return this->x; double get_y() const { szamlal++; return this->y; int get_sz() const { return szamlal; // konstans // mégis változik // konstans // mégis változik ; p.set_x(1.0); p.set_y(1.0); sz = p.get_sz(); cout << sz << " hozzaforodulas" << endl; // 0 x = p.get_x(); y = p.get_y(); sz = p.get_sz(); cout << "p.x=" << x << " p.y=" << y << " " << sz << " hozzaforodulas" << endl; // 2 9
I.2.3. Konstruktor(ok) Függvény az objektumok előkészítésére (esetleg inicializálása) Ugyanaz a neve mint az osztálynak, nincs típusa I.2.3.1 Alapértelmezett konstruktorok Ha nem adjuk meg akkor is létezik alapértelmezett (default) - X() és egy (tagonként) másoló X(const &X par) létrehozáskor (a fordító foglal) - mindkettő inicializálja az objektumpéldányt (ha új pld,-t másol akkor copy) - minden osztálynak van alapértelmezett = operátora (ha már létezik =) cember geza; // default konstruktor nincs zjel!!! cember lujza=cember(geza) // copy konstruktor hosszú dinamikusnál kell cember lujza(geza); // copy konstruktor rövid dinamikusnál nincs cout<<"geza neve:"<<geza.nev<<endl;// Geza neve: cout<<"geza kora:"<<geza.kor<<endl;// Geza kora:-858993460 geza.nev="geza"; geza.kor=18; cout<<"geza neve:"<<geza.nev<<endl;// Geza neve:geza cout<<"geza kora:"<<geza.kor<<endl;// Geza kora:18 cember malvin; malvin = geza; - konstans- és referencia tagokat tartalmazó osztálynak nem lehet alapértelmezett konstruktora (inicializálni kell!) class cember {// ha ilyen lenne int szemelyi_szám; ; int & kor; // nem tudja inicializálni ; ; no appropriate default constructor (!) cember geza; // def. értékadás létezőre = operator 10
I.2.3.2 Megadott konstruktorok Ugyanaz a neve mint az osztálynak, nincs típusa és visszatérési értéke, lehet túlterhelt Ha megadjuk a default többé nem elérhető Létrehoz, inicializálhat és területet is foglalhat Létrehozás után nem hívható class cember { int szemelyi_szám; cember(int is, string ss,int ik=0) { szemelyi_szám=is; nev=ss; kor=ik; a = new int[10]; // dinamikus helyfoglalás int * a; char szul_hely[100]; string nev; int kor; ; // objektum létrehozása // cember geza=cember(1,"lajos"); hosszú alak cember geza(1,"lajos"); // geza szemelyi_szama 1, neve Lajos, kora 0, szul_helye "" Strcpy_s(geza.szul_hely,"Budapest"); cout<<"geza neve:"<<geza.nev<<endl; cout<<"geza kora:"<<geza.kor <<endl; cout<<"geza szul helye:"<<geza.szul_hely<<endl; // csak a példa kedvéért public // csak a példa kedvéért public // csak a példa kedvéért public // csak a példa kedvéért public // megadtuk a születési helyet 11
I.2.3.2.1 Konstruktor-hívás formái Oszttip * pnev=new Oszttip(parameterek) // dinamikus // dinamikus forma // emilio szemelyi_szama 1, neve Ubul, kora 13, szul_helye "" cember * emilio = new cember(1,"ubul",13); cout<<"emil neve:"<<emilio->nev<<endl; cout<<"emil kora:"<<emilio->kor<<endl; cout<<"emil szul helye:"<<emilio->szul_hely<<endl; // nincs megadott születési hely delete emilio; Oszttip nev (parameterek) // statikus forma // emil szemelyi_szama 1, neve Ubul, kora 13, szul_helye "" cember emil(1,"ubul",13); cout<<"emil neve:"<<emil.nev<<endl; cout<<"emil kora:"<<emil.kor<<endl; cout<<"emil szul helye:"<<emil.szul_hely<<endl; // nincs megadott születési hely // ĺ< I.2.3.2.2 Egy paraméter esetén kétfajta inicializálás Oszttip nev(parameter) helyett Oszttip nev =parameter class flo { int szam; flo(int x) { szam=x; ; flo s=3.14; cout<<s.szam<<endl; // 3 flo ss(6.28); cout<<s.szam<<endl; // 6 // statikus 12
I.2.3.2.3 Explicit Konstruktorok Egyparaméteres konstruktor esetén az explicit kulcsszóval megtilthatjuk, hogy az alapértelmezett implicit konverzió alapján rövidítsen. Class Classnév{ explicit Classnev(parameter);... Classnev x=más_tip_parameter; // HIBA! class flo { int szam; explicit flo(int x) { szam=x; ; Fordítási hiba can not convert double to int (!) flo s=3.14; cout<<s.szam<<endl; 13
I.2.3.3 Másoló konstruktor I.2.3.3.1 Default másoló konstruktor A default minden tagot átmásol dinamikus terület esetén probléma class cember { int szemelyi_szám; int * a; cember(int is, string ss,int ik=0) { szemelyi_szám=is; nev=ss; kor=ik; a = new int[10]; for (int i=0; i<10; i++) a[i]=i; // dinamikus helyfoglalás // adatok //Le kell majd bontani a new által foglalt területet ; cout<<"geza a[5]="<<geza.a[5]<<endl; // 5 cember gizi(geza); cout<<"gizi a[5]="<<gizi.a[5]<<endl; gizi.a[5]=15; cout<<"geza a[5]="<<geza.a[5]<<endl; cout<<"gizi a[5]="<<gizi.a[5]<<endl; // 5 másolat // 15 mert csak a tömb pointer // 15 mert csak a tömb pointer 14
I.2.3.3.2 Definiált másoló konstruktor Megváltoztatjuk a másolást class cember { int szemelyi_szám; int *a; cember(int is, string ss,int ik=0) { szemelyi_szám=is; nev=ss; kor=ik; a = new int[10]; // dinamikus helyfoglalás for (int i=0; i<10; i++) a[i]=i; cember(const cember & c) { // átírt másoló konstruktor szemelyi_szám=c.szemelyi_szám; nev=c.nev; kor=c.kor; a = new int[10]; for (int i=0; i<10; i++) a[i]=c.a[i]; ; cout<<"geza a[5]="<<geza.a[5]<<endl; // 5 cember gizi(geza); // másolat cout<<"gizi a[5]="<<gizi.a[5]<<endl; // 5 másolat gizi.a[5]=15; cout<<"geza a[5]="<<geza.a[5]<<endl; // 5, marad cout<<"gizi a[5]="<<gizi.a[5]<<endl; // 15 15
Másoló konstruktor operator = Ha létező, akkor = Új esetén másoló #include<iostream> #include<stdio.h> using namespace std; class Test { int adat; Test(int a=0) { adat = a; Test(const Test &t){ cout << "Copy constructor" << endl; adat = t.adat; Test& operator = (const Test &t){ cout << "= operator" << endl; adat = t.adat; return *this;//ha nem referencia a visszatérés, akkor ez is hívja a copy-t ; int main() { Test t1(1); Test t2(2); t2 = t1; Test t3 = t1; Test * t4 = new Test(4); Test * t5 = new Test(5); // = operator // Copy constructor *t5 = *t4; // = operator Test * t6 = new Test(*t4); // Copy constructor 16
I.2.3.4 Tagok kezdeti értéke class nev { tip at1; Előbb lefut tip at2; Konstruktor(tip p1, tip p2 ): at1(p1), at2(p2) { ; class nev { ; Objektum, referencia és const esetén kötelező! class nev1 { int iat; float & fat; nev1(int i, float f) {iat=i; fat=f; ; float ff=1.1; nev1 pl1(1,ff); must be initialized in constructor! tip at1; tip at2; Konstruktor(tip p1, tip p2 ) { at1=p1; at2=p2; class nev2 { int iat; float & fat; nev2(int i, float f) : iat(i), fat(f){; ; float ff=1.1; nev2 pl2(1,ff); // OK 17
I.2.5 Destruktor Az objektumok megszűnésekor meghívódó függvény A neve ~osztálynév, nincs típusa (visszat.értéke), nincsenek paraméterei, nem túlterhelhető Akkor aktivizálódik, ha az objektum megszűnik (csak takarít nem a fv. szűnteti meg az obj.-t) statikus objektum érvénytelenné válhat {-kívül dinamikus objektum törölhető (delete) class cember { int szemelyi_szám; cember(int is, string ss,int ik=0) { szemelyi_szám=is; nev=ss; kor=ik; a = new int[10]; // dinamikus helyfoglalás int * a; ~cember() { delete [] a; // törlés megszüntetéskor ; cember * jonas= new cember(1,"janos",26); cout<<"jonas neve:"<<jonas->nev<<endl; cout<<"jonas kora:"<<jonas->kor<<endl; strcpy(jonas->szul_hely,"budapest"); cout<<"jonas szul helye:"<<jonas->szul_hely<<endl; cout<<"jonas a[5]:"<<jonas->a[5]<<endl; delete jonas; 18