Fizikus C++ labor

1. hét: make és C ismétlés2. hét: pontosság és pontatlanság3. hét: azonos nevű függvények, referencia
4. hét: egyszerű osztályok5. hét: konstruktor és operator overloading6. hét: osztály dinamikus adattaggal
9. hét: >> és << használata I/O-ra, statikus tagok10. hét / 1: STL vector10. hét / 2: STL string, algorithm
11. hét: generikus algoritmusok és osztályok12. hét: öröklés13. hét: heterogén kollekció
14. hét: C++11 kitekintő15. hét: Nagyházi bemutatás

11. hét: öröklés

1. feladat

a) Készíts Ember osztályt, amely egy ember adatait tárolja: neve (std::string), kora (int), neme (bool).

-- Az adatok legyenek privátok!

-- Készíts konstruktort, amely beállítja a három tulajdonságot,

-- készíts getter és setter függvényeket a tulajdonságok lekérdezéséhez ill. beállításához!

-- Készíts print függvényt, amely kiírja az ember adatait a cout-ra!

b) Készíts Focista osztályt, aki egy fajta Ember! A focista tartsa nyilván az általa rúgott gólok számát (int), valamint a válogatottságainak számát (int) privát adatként!

-- Készíts konstruktort, amellyel beállíthatod a focista összes tulajdonságát! A focista is ember, tehát az ember tulajdonságait is be kell állítani. Mivel az ember adatai privát változókban vannak, ezekhez közvetlenül nem férhetsz hozzá. Érdemes a beállítást az s konstruktorának meghívásval megtenni. (Az s konstruktora csak a konstruktor inicializáló listáján hívható.)

-- Készíts getter/setter függvényeket a focista tulajdonságainak lekérdezéséhez/beállításához!

-- Készíts print függvényt, amely kiírja a focista tulajdonságait, beleértve az emberi tulajdonságait is! Az emberi tulajdonságok kiírásához az s osztály kiíró függvényét hívd meg!

c) Írj main fggvényt, amelyben kipróbálod a megírt osztályokat! Gy z dj meg róla, hogy a focista esetében meg tudod hívni az ember lekérdez /beállító függvényeit is!

2. feladat

A 6. héten készített vektor osztályból hozz létre örökléssel egy SIvektor osztlyt, ahol a SI a sztringgel indexelhet t jelenti! Ez egy olyan osztály, ahol nem csak az elem sorszámával, hanem szöveggel is lekérdezheted az elemeket. Pl. a következ módon használható:

int main(){
    try{
        SIvektor v;
        v.push_back("hetfo", 22.5);
        v.push_back("kedd", 17.3);
        v.push_back("szerda", 15.4);
        v.push_back("csutortok", 19.8);
        v.push_back("pentek", 25.0);
        v.push_back("szombat", 21.7);

        std::cout << v["kedd"] << std::endl;
        std::cout << v[4] << std::endl;

        SIvektor v2 = v;
        std::cout << v2["szerda"] << std::endl;

        SIvektor v3;
        v3 = v;
        std::cout << v3["szombat"] << std::endl;

        std::cout << v["vasarnap"] << std::endl; // kiv telt dob
    }
    catch (const std::invalid_argument &hiba){
        std::cerr << "Hiba: " << hiba.what() << std::endl;
    }
    return 0;
}

-- A push_back és az [] operátor paraméterében "valami" módon megadott C sztringek vannak, melyeknek a típusa const char *. A push_back és [] op. függvények megírásakor azonban használhatunk const std::string & típusú paramétert, mert van amutomatikus típuskonverzió.

-- A sztringeket tárolhatjuk a vektor osztályhoz hasonlóan egy std::string *st; dinamikus tömbben, melynek mérete mindig megegyezik a double tömbbével így a méretet nem kell mégegyszer tárolni, de érdemesebb talán az STL vectort használni a tároláshoz, azaz std::vector<std::string> sztringtomb; változót létrehozni, ezzel sokkal egyszer bb lesz a kód. (A mintamegoldásban ez utóbbi szerepel.)

-- Készítsük el a kétparaméteres push_back függvényt! Ha std::vectorba tettük a sztringeket, akkor a függvény kódja két utasítás: az s osztály push_back függvényének meghívása és a sztringtomb push_back függvényének meghívása. Az sben publikus függvény volt a push_back. Vajon m ködne, ha a ain-be beírnánk, hogy v.push_back(12.3); ? Miért?

-- Készítsük el az [] operátort, melynek paramétere egy sztring! A függvényen el ször egy ciklussal járjuk végig a sztringtömböt, és ellen rizzük, hogy benne van-e a paraméterként kapott sztring. Ha igen, akkor visszaadhatjuk az elemet az sosztály [] operátorának meghívásával. Ha nincs, akkor dobjunk invaid_argument kivételt!

-- Mivel írtunk [] operátort a leszármazotban, ezért az sben definiált [] operátor nem hívható meg közvetlenül, azaz a fenti main függvényben megadott std::cout << v[4] << std::endl; kód nem m ködik. Ha megírjuk az int paramétert kapó [] operátort is a SIvektor osztályban, akkor már m ködni fog. Ebbe csak egy utasítás kell: az s index operátorának meghívása (return vektor::operator[](i);).

-- Ha dinamikus tömbben tároltuk a sztringeket, akkor el kell kszítenünk a destruktort, másoló konstruktort és = operátort is. A másoló ctor és az = op meg kell hívja az s másoló ctor ill. = op függvényét, majd a sztringek tömbjét is át kell másolnunk. A destruktor automatikusan meghívja az s destruktorát, kézzel nem kell és nem is szabad.

-- Ha std::vectorban tároltunk a sztringeket, akkor nem szükséges sem destruktort, sem másoló ctort, sem = op-t írnunk, mart jó lesz az automatikus. Most, a gyakrlás kedvéért mégis írjuk meg a másoló ctor-t és az = op-t. Az std::vector =-vel másolható.

-- Ha megírtuk a másoló ctort, akkor kell írnunk alapértelmezett ctor-t is, mert nem jön létre automatikusan. Ennek törzse dinamikus tömb esetén st=NULL;, std::vector esetén üres.

Emlékeztet ül a vektor osztály:

class vektor{
    double *t;
    int n;
public:
    vektor() :t(NULL), n(0){ std::cout << "****************" << std::endl; }
    ~vektor(){ delete[]t; }
    vektor(const vektor &masik);
    const vektor &operator=(const vektor &masik);
    double &operator[](int i){
        if (i < 0 || i >= n)throw std::out_of_range("vektor::operator[]: out of range");
        return t[i];
    }
    const double &operator[](int i)const{
        if (i < 0 || i >= n)throw std::out_of_range("vektor::operator[]: out of range");
        return t[i];
    }
    void push_back(double);
    int getSize()const{ return n; }
};

vektor::vektor(const vektor &masik) :n(masik.n){
    t = new double[n];
    for (int i = 0; i < n; i++)
        t[i] = masik.t[i];
}

const vektor &vektor::operator=(const vektor & masik){
    if (this == &masik)
        return *this;
    delete[]t;
    n = masik.n;
    t = new double[n];
    for (int i = 0; i < n; i++)
        t[i] = masik.t[i];
    return *this;
}

void vektor::push_back(double uj){
    double *p = new double[n + 1];
    for (int i = 0; i < n; i++)
        p[i] = t[i];
    p[n] = uj;
    n++;
    delete[]t;
    t = p;
}

Mintamegoldások

1. feladat
#include <iostream>
#include <string>

class Ember{
    std::string nev;
    int kor;
    bool lany_e; // tfh ha nem l ny, akkor fi 
public:
    Ember(const std::string &nev, int kor, bool lany_e) :nev(nev), kor(kor), lany_e(lany_e){}
    const std::string &getNev()const{ return nev; }
    int getKor()const{ return kor; }
    bool getLany_e()const{ return lany_e; }
    bool fetFiu_e()const{ return !lany_e; }
    void setNev(const std::string &ujnev){ nev = ujnev; }
    void setKor(int ujkor){ kor = ujkor; }
    void setLany_e(bool lany_e){ this->lany_e = lany_e; }
    void setFiu_e(bool fiu_e){ lany_e = !fiu_e; }
    void print()const{
        std::cout << "Nev: " << nev << "\nKor: " << kor 
            << "\nNeme: " << ( lany_e ? "Lany" : "Fiu" ) << std::endl;
    }
};

class Focista :public Ember{
    int golok, valogatott;
public:
    Focista(const std::string &nev, int kor, bool lany_e, int gol, int valogatott)
        :Ember(nev, kor, lany_e), golok(gol), valogatott(valogatott){}
    int getGol()const{ return golok; }
    int getValogatott()const{ return valogatott; }
    void setGol(int gol){ golok = gol; }
    void setValogatott(int valogatott){ this->valogatott = valogatott; }
    void print()const{
        Ember::print();
        std::cout << "Gol: " << golok << "\nValogatott: " << valogatott << std::endl;
    }
};

int main(){
    Ember e("Feles Elek", 115, false);
    Focista f("Rugolabu Juliska", 19, true, 847, 12);
    e.print();
    f.print();
    f.setNev("Virgonc Odon");
    f.setFiu_e(true);
    f.setGol(55);
    f.setValogatott(0);
    f.print();
    return 0;
}

 

2. feladat
class SIvektor :public vektor{
    std::vector sztringtomb;
public:
    void push_back(const std::string & index, double d){
        vektor::push_back(d);
        sztringtomb.push_back(index);
    }
    double &operator[](const std::string &si){
        int i;
        for (i = 0; i < sztringtomb.size() && sztringtomb[i] != si; i++)
            ;
        if (i == sztringtomb.size())
            throw std::invalid_argument("invalid indexing string");
        return (*this)[i];
    }
    const double &operator[](const std::string &si)const{
        int i;
        for (i = 0; i < sztringtomb.size() && sztringtomb[i] != si; i++)
            ;
        if (i == sztringtomb.size())
            throw std::invalid_argument("invalid indexing string");
        return (*this)[i];
    }
    double &operator[](int i){
        return vektor::operator[](i);
    }
    const double &operator[](int i)const{
        return vektor::operator[](i);
    }
    SIvektor(const SIvektor &masik) :vektor(masik){ // most jo lenne az automatikusan keletkezo is
        sztringtomb = masik.sztringtomb;
    }
    SIvektor(){} // ha irunk masolo ctort, ez is kell, automatikusan hivja az os alapertelmezett ctort
    const SIvektor &operator=(const SIvektor &massik){ // most jo lenne az automatikusan keletkezo is
        vektor::operator=(massik);
        sztringtomb = massik.sztringtomb;
        return *this;
    }
};