13. elődás

Tipp: a diák között lépkedni a J és K billentyúkkel lehet. Szöveges kereséshez ctrl-F használható.

Letöltés

1.

Programozás alapjai II. (13. ea) C++ OO tervezési megfontolások Goldschmidt Balázs Szeberényi Imre BME IIT <balage@iit.bme.hu> M Ű E GY E T E M 1 7 82 C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 1-

2.

NHF beadás • Feltöltendő állományok: – Ne használjon ékezetes karaktereket az állományok nevében! – Forrásfájlokat tartalmazó zip fájlban ne legyen alkatalógus (fájlok az archívum gyökérében legyenek). – Adatfájlokat tartalmazó zip fájl (opcionális). Tartalma abba a katalógusba másolódik, ahol a program fut. – Bemeneti adatfájl, melynek tartalmát futtatáskor a program szabványos bemenetére továbbítjuk. – Dokumentáció feltöltése a feladat kiértékeléséhez nem szükséges, csak a végleges beadásnál elvárt, hiánya a megoldás elutasítását vonja maga után. C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 2-

3.

Standard input C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 3-

4.

Jporta környezet • Linux (nincs widows.h) • Zip-ben feltöltött fájlok változatlanul kerülnek bemásolásra. Ezek tartalmazhatnak bináris adatot is, ami architektúra függő lehet! • Unix/Linus alatt nics a szövegfájl megkülönböztetve. – DOS-ból Windows-ból hozott szövegfájl sorainak végén \r\n karaktersorozat van, amit get(), ignore() 2 db karakternek kezel! C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 4-

5.

Bináris vs Text • A szövegfájlokban a sorok végét a különböző operációs rendszerek különböző módon jelölik: – \n – \r\n – \n\r - UNIX/Linux, Mac OS - MS DOS/Windows, VMS, - régi Mac OS • A bajok ebből származnak, de persze a kódkészlet is okoz gondot. C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 5-

6.

Bináris vs Text /2 • A C nyelv a UNIX-szal együtt fejlődött ki, a C programok sokezelési logikája erre épül. Így a nyelvben csak a \n-t szokás használni. • Ehhez az \r\n ill. \r sorvéget tároló rendszerek úgy alkalmazkodtak, hogy bevezették a bináris/text módot. • Text módban megnyitott fájlból olvasáskor a ténylegesen tárolt sorvégből (pl \r\n) egyetlen \n karaktert gyártanak. Íráskor pedig a \n-ből a ténylegesen tárolt sorvéget (pl. \r\n sorozatot). C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 6-

7.

Bináris vs Text /3 • Mivel a UNIX/Linux rendszerekben nem kell a program logikája és a tényleges tárolt sorvégek között konvertálni, így ezekben a rendszerekben a bináris és text mód között nincs működésbeli különbség. • A rendszerben alapvetően nem keletkeznek, de kívülről érkezhetnek más formátumú fájlok. • Ezek kezelése: – Fájlkonverzió (dos2unix, unix2dos, tr, ... ) – Program szintű kezelés. C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 7-

8.

C++ szintű kezelés • Általában a white-space karaktereket eldobjuk gyarkran még a sorstruktúra sem érdekes. • Alapesetben a skipws be van kapcsolva, ami a white-space karakterek eldobását jelenti. Ezt az extractor egy mezei karakter beolvasásánál is figyelembe veszi. pl: – – – – char c; std::cin >> c; // c-be csak nem white-space kar kerül. std::cin >> noskipws >> c; // bármi std::cin.get() // független a skipws-től, de Windows/UNIX függő std::getline() // független a skipws-től, de Windows/UNIX függő • Ha mégis fontos a sorstruktúra ismerete, akkor a getline() többnyire minden további nélkül alkalmazható. A sor végén pedig OS-től függően lesz egy \r. C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 8-

9.

Hordozható getline #include <iostream> #include <string> namespace cp { //cross-platform getline std::istream& getline(std::istream& is, std::string& str) { std::getline(is, str); if (str.size() && *str.rbegin() == '\r') str.erase(str.size()-1); return is; } Használat: cp::getline(.....) https://git.ik.bme.hu/Prog2/ell_feladat/NHF C++ programozási nyelv © BME-IIT Sz.I. kesz/cross_paltform.h 2019.05.14. - 9-

10.

memtrace működés • makrókkal lecseréli a new és delete kulcsszavakat sajét függvényre, ami ellenőriz. • C++11-ben a delete tagfüggvény törlésre is használható az osztály deklarációjában. A makró ezt is lecseréli, amiből baj van. • Megoldás: Ezeket az header fájlokat a memtrace.h előtt kell include-olni. – „Kézzel” – Automatikusan C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 10 -

11.

memtrace include A memtrace.h azokat a standard fejléc állományokat, amelyek használják a delete kulcsszót automatikusan include-olja. A fejlesztő környezetek azonban változnak. Így a memtrece.h-t folyamatosan frissíteni kell. A legutolsó memtrace változat a https://git.ik.bme.hu/Prog2/ell_feladat/Test projektben érhető el C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 11 -

12.

Tervezési feladat • Készítsünk számológépet! – matematikai kifejezéseket kell modellezni • pl. 3+4*(5-2) – alapműveletek • +-*/ – egész számok • pl 1, 2, 3, 13 – a beolvasás most mellékes C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 12 -

13.

Kifejezések modellezése • Kifejezés: számok és műveletek • Számok felelőssége – megmondja, mennyit tárol • Műveletek felelőssége – van operandusa (bal, jobb) – kiszámolja a művelet eredményét – mi lehet operandus? • művelet vagy szám → heterogén kollekció → öröklés – hogyan kapunk eredményt? Metódussal! C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 13 -

14.

Kifejezés osztály és leszármazottai 2 Expression #op +evaluate(): int Operator Value - value +evaluate(): int +evaluate(): int Addition +evaluate(): int Multiplication Subtraction +evaluate(): int +evaluate(): int C++ programozási nyelv © BME-IIT Sz.I. Division +evaluate(): int 2019.05.14. - 14 -

15.

C++ megvalósítás • Expression class Expression { public: virtual int evaluate() const = 0; // absztrakt metódus virtual ~Expression() {} }; C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 15 -

16.

C++ megvalósítás • Value class Value : public Expression { int value; public: Value(int v = 0) : value(v) {} int evaluate() const; }; int Value::evaluate() const { return value; } C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 16 -

17.

C++ megvalósítás • Operator – hogyan hivatkozzunk az operandusokra? • referencia vs pointer – referencia • nem kell memóriakezeléssel foglalkozni • csak egyszer állítható (konstruktor) – pointer • memóriakezelés kérdéses – másolás, destruálás, stb… • konstruálás után is beállítható, módosítható C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 17 -

18.

C++ megvalósítás • Operator – használjunk pointert • memóriakezelést később class Operator : public Expression { protected: Expression * op[2]; public: Operator(Expression * e1, Expression * e2) { op[0] = e1; op[1] = e2; } void setOperand(Expression * e, int n) { op[n] = e; } }; C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 18 -

19.

C++ megvalósítás • Addition – Operator leszármazottja • operandusok, evaluate class Addition : public Operator{ public: Addition(Expression * e1, Expression * e2) : Operator(e1,e2) {} int evaluate() const; }; int Addition::evaluate() const { return op[0]->evaluate() + op[1]->evaluate(); } C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 19 -

20.

C++ megvalósítás • Multiplication, Subtraction, Division – Mint Addition, csak evaluate más …. int Multiplication::evaluate() const { return op[0]->evaluate() * op[1]->evaluate(); } int Subtraction::evaluate() const { return op[0]->evaluate() - op[1]->evaluate(); } int Division::evaluate() const { return op[0]->evaluate() / op[1]->evaluate(); } C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 20 -

21.

C++ megvalósítás • Egyszerű példa a használatra 3+4 Value v3(3); Value v4(4); Addition a(&v3, &v4); cout << a.evaluate() << endl; C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 21 -

22.

C++ megvalósítás • Összetett példa a használatra 3+(4*(5-2) 3+(4*(5-2)) + 3 * 4 5 2 Value v2(2), v3(3), v4(4) , v5(5) ; Subtraction s(&v5, &v2); Multiplication m(&v4, &s); Addition a(&v3, &m); cout << a.evaluate() << endl; // 15 C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 22 -

23.

C++ megvalósítás • Összetett példa a használatra 3+(4*(4-2) 3+(4*(4-2)) + 3 Value v2(2), v3(3), v4(4) , v5(4) ; Subtraction s(&v5, &v2); Multiplication m(&v4, &s); Addition a(&v3, &m); * 4 4 2 Ilyen már van! cout << a.evaluate() << endl; // 11 C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 23 -

24.

C++ megvalósítás • Összetett példa a használatra 3+(4*(4-2) 3+(4*(4-2)) + 3 * 2 4 Value v2(2), v3(3), v4(4) , v5(4) ; Subtraction s(&v4, &v2); Multiplication m(&v4, &s); Addition a(&v3, &m); cout << a.evaluate() << endl; // 11 https://git.ik.bme.hu/Prog2/eloadas_peldak/ea_13 C++ programozási nyelv © BME-IIT Sz.I. szamologep 2019.05.14. - 24 -

25.

Memóriakezelés • Pointereket tárolunk – a példában lokális változók → automatikusan megszűnnek – mi van, ha dinamikus? Ki szabadítja fel? • Felszabadítás beépítve (kompozíció) – mindig dinamikus a foglalás – egy példány csak egy operátornál • Felszabadítás külön kezelve – ki csinálja? C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 25 -

26.

Factory objektum • Felelősség – új objektum létrehozása – munka végén rendet rak • Műveletek – add(Expression* e1 = null, Expression* e2 = null) – div(…), mult(…), sub(…) – val(int value) • ha korábban már létrehoztuk, jó a régi • a többszörözést is el tudjuk kerülni C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 26 -

27.

Factory megvalósítás • Összetett példa a factory használatára 3+(4*(4-2) Factory f; Subtraction *s = f.sub(f.val(4), f.val(2)); Multiplication *m = f.mult(f.val(4), s); Addition *a = f.add(f.val(3), m); cout << a->evaluate() << endl; // 11 // f destruktora felszabadít minden létrehozott objetumot https://git.ik.bme.hu/Prog2/eloadas_peldak/ea_13 C++ programozási nyelv © BME-IIT Sz.I. szamologep 2019.05.14. - 27 -

28.

Factory megvalósítás class Factory { list<Expression*> created; // vector? map<int, Value*> values; public: Value* val(int i) ; Addition* add(Expression * e1, Expression * e2); … ~Factory() { while (!created.empty()) { delete created.front(); created.pop_front(); } } }; C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 28 -

29.

Factory megvalósítás Value* Factory::val(int i) { if (values[i] == null) { values[i] = new Value(i); created.push_back(values[i]); } return values[i]; } Addition* Factory::add(Expression * e1, Expression * e2) { Addition* a = new Addition(e1, e2); created.push_back(a); return a; } C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 29 -

30.

Változók • Legyenek változóink! x*3+z*y – az értéküket lehessen központilag állítani – minden kiértékelésnél az aktuális értékkel számoljanak Variable v1("x"), v2("y"), v3("z"); Value v(3); Expression *e = f.add(f.mult(&v1, &v), f.mult(&v3, &v4)); e->evaluate(); // ?????????? C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 30 -

31.

Változók értéke hol? • Be van drótozva Variable-be – akkor miért változó? • Globális tárban tároljuk – hogyan tudjuk ugyanazt a kifejezést kiértékelni különböző számokra? – pl. v = s/t → div("s", "t"); • Kiértékelés előtt állítjuk be – setContext(Context* c) – nem kiértékelés, hanem objektum-specifikus • A kifejezésnek kiértékeléskor adjuk át – int evaluate(Context* ctx) – módosítani kell a kiértékelő függvényt – ez a korrekt megoldás (lokális tudás) C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 31 -

32.

Kontextus objektum szinten Expression Context 2 +evaluate(): int +setContext(c: Context) +getVar(v: string): int #op +setVar(v: string, i: int) Value Operator Variable -value -name +evaluate(): int +evaluate(): int +evaluate(): int Addition +evaluate(): int Multiplication Subtraction +evaluate(): int +evaluate(): int C++ programozási nyelv © BME-IIT Sz.I. Division +evaluate(): int 2019.05.14. - 32 -

33.

Változók megvalósítása class Context { map<string, int> values; public: void setVar(string s, int i) { values[s] = i; } int getVar(string s) { return values[s]; } }; class Variable : public Expression { string name; public: Variable(string n = "x") : name(n) {} int evaluate() const { return ctx->getVar(name); } Valahonnan ismerni kell. }; Örököljük az expression-ből! C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 33 -

34.

Meglevő osztályok bővítése class Expression { protected: Context* ctx; public: virtual void setContext(Context* c) { ctx = c; } … // többi marad }; class Operator { public: void setContext(Context* c) { Expression::setContext(c); op[0]->setContext(c); op[1]->setContext(c); } … // többi marad }; C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 34 -

35.

Változók kontextussal • Értékeljük ki: x*3+z*y x = 5, y = 6, z = 7 Variable vx("x"), vy("y"), vz("z"); Value v(3); Expression *e = f.add(f.mult(&vx, &v), f.mult(&vz, &vy)); Context ctx; ctx.setVar("x", 5); ctx.setVar("y", 6); ctx.setVar("z", 7); e->setContext(&ctx); cout << e->evaluate() << endl; https://git.ik.bme.hu/Prog2/eloadas_peldak/ea_13 C++ programozási nyelv © BME-IIT Sz.I. szamologep2 2019.05.14. - 35 -

36.

Kontextus metódus szinten Expression Context 2 +getVar(v: string): int +evaluate(c:Context): int #op +setVar(v: string, i: int) Value Operator -value +evaluate(c: Context): int Addition +evaluate(c: Context): int Multiplication +evaluate(c: Context): int C++ programozási nyelv © BME-IIT Sz.I. Subtraction +evaluate(c: Context): int Variable -name +evaluate(c: Context): int +evaluate(c: Context): int Division +evaluate(c: Context): int 2019.05.14. - 36 -

37.

Változók megvalósítása class Context { map<string, int> values; public: void setVar(string s, int i) { values[s] = i; } int getVar(string s) { return values[s]; } }; class Variable : public Expression { string name; public: Variable(string n = "x") : name(n) {} int evaluate(Context& ctx) const { return ctx.getVar(name); } Metódus parmétereként kapjuk }; C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 37 -

38.

Meglevő osztályok bővítése class Expression { public: virtual int evaluate(Context& c) const = 0; … // többi marad }; // többi osztályban is módosul a metódus fejléce C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 38 -

39.

Változók kontextussal • Értékeljük ki: x*3+z*y x = 5, y = 6, z = 7 Variable vx("x"), vy("y"), vz("z"); Value v(3); Expression *e = f.add(f.mult(&vx, &v), f.mult(&vz, &vy)); Context ctx; ctx.setVar("x", 5); ctx.setVar("y", 6); ctx.setVar("z", 7); cout << e->evaluate(ctx) << endl; C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 39 -

40.

Változók Factoryban • Factory gyártsa a változókat is – most mindegyik új, memóriakezelés nincs megoldva – lehetne itt is csak újat létrehozni, mint Valuenál. // Factory osztályba új metódus deklarációja kerül // alább pedig a definíció Variable* Factory::var(string s) { Variable* v = new Variable(s); created.push_back(v); return v; } C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 40 -

41.

Változók Factoryban • Értékeljük ki: x*3+z*y x = 5, y = 6, z = 7 Factory f; Variable *vx = f.var("x"), *vy = f.var("y"), *vz = f.var("z"); Value* v =f.val(3); Expression* e = f.add(f.mul(vx, v), f.mul(vz, vy)); Context ctx; ctx.setVar("x", 5); ctx.setVar("y", 6); ctx.setVar("z", 7); cout << e->evaluate(ctx) << endl; C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 41 -

42.

Mi a kifejezések típusa? • Most a megoldás int-tel dolgozik • Lehessen bármi ☺ → Sablon! – ehhez mindent ki kell bővíteni • template <class T>, Expression<T>, stb • minden .h + .cpp -> .hpp – öröklésnél vigyázni • using az örökölt tagváltozók elérése előtt pl. using Expression<T>::ctx; // setContext változat – innentől minden működik, ami kellhet • int, double, Complex, stb https://git.ik.bme.hu/Prog2/eloadas_peldak/ea_13 C++ programozási nyelv © BME-IIT Sz.I. szamologep3 2019.05.14. - 42 -

43.

Merre tovább? • Bővítések – egyoperandusú műveletek • negálás, gyökvonás, reciprokképzés, stb – függvények • bemenő paraméterek: változók (Variables) • törzs: kifejezés (Expression) • meghívás: proxy objektummal: bemeneti kifejezések kiértékelése, fv törzs lefuttatása – stb. C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 43 -

44.

Bővített osztálydiagram SQRT Unary 1 #op Negate #param Expression * Context 2 +getVar(v : string): int +setVar(v : string, i: int) #op Operator +evaluate(c: Context): int A ddition Multiplication Subtraction +ev aluate(c: Context): int +ev aluate(c: Context): int +ev aluate(c: Context): int C++ programozási nyelv © BME-IIT Sz.I. FunCall +evaluate(c:Context): int +body Value -v alue +ev aluate(c: Context): int Variable -name #param Function * +ev aluate(c: Context): int Division +ev aluate(c: Context): int 2019.05.14. - 44 -

45.

Egyváltozós függvény • pl. f(x) = x*x class Function { Expression* expr; Variable* param; public: Function(Expression* e, Variable* p) : param(p), expr(e) {} int evaluate(Context& ctx, Expression* ap) { Context c2(ctx); c2.setVar(param->getName(), ap->evaluate(ctx)); return expr->evaluate(c2); } }; C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 45 -

46.

Egyváltozós függvény • hivatkozás, pl. 4+f(5+3)*2+f(2) class FunCall : public Expression { Function * f; // meghívandó függvény Expression* p; // függvény paramétere ez a kifejezés public: FunCall(Function * f, Expression* e) : f(f), p(e) {} int evaluate(Context& ctx) const { return f->evaluate(ctx, p); } }; C++ programozási nyelv © BME-IIT Sz.I. 2019.05.14. - 46 -

47.

Egyváltozós függvény • használat, pl.: f(t)=t*t; f(a)+f(b), ha a=3, b=4 Context ctx; Variable t("t"); Multiplication m(&t, &t); Function f(&m, &t); Variable a("a"), b("b"); FunCall a2(&f, &a), b2(&f, &b); Addition ad(&a2, &b2); ctx.setVar("a", 3); ctx.setVar("b", 4); cout << ad.evaluate(ctx) << endl; https://git.ik.bme.hu/Prog2/eloadas_peldak/ea_13 C++ programozási nyelv © BME-IIT Sz.I. szamologep3 2019.05.14. - 47 -

Utolsó frissítés: 2019-05-07 09.47