Nem-OO nyelvi elemek

A mai óra célja a fontosabb nem-OO nyelvi elemek elsajátítása, és az OO előkészítése.

Felkészülés a gyakorlatra

1. Referencia fogalma

A gyakorlatvezető segítségével ismételjétek át a referencia fogalmát! Hogyan érdemes tekinteni a referenciákra? Mit szabad és mit nem szabad velük?

Összefoglaló
  • A referencia nem egy pointer, hanem az eredeti változó maga (álnéven, fantomként, valami ilyesmi).
  • A referencia nem lehet null.
  • A referencia nem állítható át másik változóra.
  • Ha az a kérdés, mit szabad egy referenciával, és mit nem, akkor "olyan, mint egy pointer", mert a háttérben mindig az van.
  • A függvény dönti el, hogy a paramétereit érték vagy referencia szerint kéri.
  • A referencia lehet balérték. Példa:
int& kisebb(int& a, int& b)
{
    return a < b ? a : b;
}

int main()
{
    int a = 5;
    int b = 4;
    kisebb(a, b) = 0;

    std::cout << a << " " << b << std::endl;
}

2. const fogalma

A gyakorlatvezető segítségével ismételjétek át a const fogalmát! Mit jelent, mire vonatkozik, mire jó?

Összefoglaló
  • A const arra vonatkozik, ami tőle balra van, kivéve amikor legbaloldalt van.
  • A const nem feltétlenül azt jelenti, hogy az a változó nem változtatható meg, hanem hogy azon a néven nem változtatható meg.
  • Tehát egy const bármikor rákerülhet egy változóra, de nem szedhető le róla kulturáltan.
  • Pointereknél, pl. const char* const melyik const mit jelent (rajz), 4 lehetőség. char**-nál már 8.

Referencia és const használatával elkülönül egymástól a kódban az

  • X* mint pointer / tömb,
  • X& mint változtatandó paraméter, és
  • X const& mint drágán másolható paraméter.

3. Függvény-overload fogalma

A gyakorlatvezető segítségével ismételjétek át a függvény-overload fogalmát! Mit jelent, mikor melyik függvény hívódik?

Összefoglaló
  • Ugyanazon a néven több függvény.
  • A hívás helyén, a konkrét argumentumok döntik el, hogy mikor melyik.
  • Ambiguous overload: nem egyértelmű, melyik kell.

Mi kell ahhoz, hogy az alábbi kód működjön? Írjuk meg a kisebb függvényt!

void valami_C_szar(int * valami);

int main()
{
    int a = 5;
    int b = 4;
    kisebb(a, b) = 0; // !
    std::cout << a << " " << b << std::endl;
    std::cout << kisebb(3, 4) << std::endl;

    valami_C_szar(&kisebb(a, b));
}
Megoldás
int& kisebb(int& a, int& b)
{
    return a < b ? a : b;
}

int const& kisebb(int const& a, int const& b)
{
    return a < b ? a : b;
}

4. Halmaz típus

Feladat: kapunk két fájlnevet, a fájlok tele vannak valós számokkal. Mondjuk meg, hogy melyik számok szerepeltek mindkét fájlban!

Kiindulási alapnak vegyük azt az interfészt, amit Prog1 9. gyakorlatán megírtunk!

/* inicializalatlan strukturat hoz alapallapotba */
void halmaz_init(Halmaz *ph);
/* halmazt felszabadit az utolso hasznalat utan */
void halmaz_felszabadit(Halmaz *ph);
/* igazzal ter vissza, ha benne van az adott elem */
bool halmaz_benne_van_e(Halmaz *ph, double mi);
void halmaz_betesz(Halmaz *ph, double mit);
void halmaz_kivesz(Halmaz *ph, double mit);
/* kilistazza egy halmaz tartalmat */
void halmaz_kiir(Halmaz *ph);

Milyen lehetőségeink vannak az adatszerkezetre?

Megoldás
  • Statikus tömb pl. 256 elemmel, rendezetlenül
  • Dinamikus tömb, rendezetlenül
  • Dinamikus tömb, rendezve
  • Láncolt lista, rendezve vagy rendezetlenül. Az összes közül a legrosszabb ötlet.
  • Bináris fa. Ez lenne a legjobb, de egy baj van, a halmaz_kivesz algoritmusa nem volt Prog1-en.

Válasszuk az első megoldást, mert még nem akarunk memóriakezeléssel foglalkozni (majd 3 hét múlva). Ha betelik a halmaz, lehet kivételt dobni, std::length_error pont erre való.

struct Halmaz 
{
    int db;
    double adat[256];
};

Alakítsuk ezt át, hogy használja az eddig megismert nyelvi elemeket!

Megoldás
  • Halmaz* helyett Halmaz&
  • Ahol lehet, Halmaz& helyett Halmaz const&
void halmaz_init(Halmaz& h);
void halmaz_felszabadit(Halmaz& h);
bool halmaz_benne_van_e(Halmaz const& h, double mi);
void halmaz_betesz(Halmaz& h, double mit);
void halmaz_kivesz(Halmaz& h, double mit);
void halmaz_kiir(Halmaz const& h);

A halmaz_felszabadit így üres lesz, de a halmaz_init-tel együtt maradjon meg párban, hogy könnyen át lehessen írni dinamikusra! Amennyi a malloc, annyi a free!

A fenti függvények felhasználásával írjuk meg a feladat megoldásához szükséges függvényeket, és a főprogramot!

Megoldás

Szükséges függvények:

void fajlok_metszete(char const *fajl1, char const* fajl2);
Halmaz halmaz_beolvas(char const * fajl);
Halmaz halmaz_metszet(Halmaz const& h1, Halmaz const& h2);

halmaz.cpp letöltése

5. További feladatok

  • Írd meg az alábbi függvényeket! Puskázhatsz a fent linkelt Prog1 gyakorlat megoldásaiból.
void halmaz_init(Halmaz& h);
void halmaz_felszabadit(Halmaz& h);
bool halmaz_benne_van_e(Halmaz const& h, double mi);
void halmaz_betesz(Halmaz& h, double mit);
void halmaz_kivesz(Halmaz& h, double mit);
void halmaz_kiir(Halmaz const& h);
  • Alakítsd át a Halmaz típust és a függvényeit, hogy dinamikus tömbön dolgozzanak!
  • Alakítsd át a Halmaz típust és a függvényeit, hogy rendezett tömbön dolgozzanak! Melyik függvény mennyit gyorsul ezáltal?