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

6. hét: osztály dinamikus adattaggal

Nagy HF

A követelmények és pár mintafeladat a http://www.eet.bme.hu/vieea026/HF/ oldalon találhatók. A feladat szabadon választott, tehát örülünk, ha valaki saját feladatot hoz.

Megjegyzések az oldalon felsorolt követelményekkel kapcsolatban (ezek a megjegyzések csak a saját csoportomban érvényesek):

0. feladat

Tagfüggvénnyel csak akkor valósítható meg egy kétoperandusú m velet, ha az operátortól balra saját objektum áll, mert annak az objektumnak lesz a megvalósított operátor a tagfüggvénye. Nézzük meg, milyen lehet ségeink vannak Vec2D objektum és valós szám szorzására!

 

a) Vec2D * double. Itt a *-tól balra saját objektum áll, ennek tagfüggvényeként megvalósíthatjuk az operátort. Megvalósíthatjuk globális függvénnyel is. Amelyik jobban tatszik.

 

tagfüggvénnyel
class vec2D{
    double x, y;
public:
    vec2D(double x = 0, double y = 0) :x(x), y(y){}
    double getX()const{ return x; }
    double getY()const{ return y; }
    vec2D operator*(double d)const{ return vec2D(x*d, y*d); }
};

 

globális függvénnyel
class vec2D{
    double x, y;
public:
    vec2D(double x = 0, double y = 0) :x(x), y(y){}
    double getX()const{ return x; }
    double getY()const{ return y; }
};

vec2D operator*(const vec2D &v, double d){
    return vec2D(v.getX()*d, v.getY()*d);
}

 

globális függvénnyel, ha nincs getter: friend
class vec2D{
    double x, y;
    friend vec2D operator*(const vec2D &, double);
public:
    vec2D(double x = 0, double y = 0) :x(x), y(y){}
};

vec2D operator*(const vec2D &v, double d){
    return vec2D(v.x*d, v.y*d);
}

Friend-ként deklaráljuk, így hozzáfér a privát dolgokhoz. Mindegy, hogy a friend deklaráció az osztály private vagy public részében van, nincs semmi hatással a friend-re. Lehet leg ne haszáljunk friend-et, a getteres megoldás sokkal jobb.

 

friend függvény definíciója az osztályban
class vec2D{
    double x, y;
    friend vec2D operator*(const vec2D &v, double d){
        return vec2D(v.x*d, v.y*d);
    }
public:
    vec2D(double x = 0, double y = 0) :x(x), y(y){}
};

Lehetséges, hogy a friend függvényt teljes egészében az osztálydekalrációban írjuk meg. Ett l ez nem lesz tagfüggvény, továbbra is globális függvény marad. Más szóval: ha egy függvény el tt szerepel a friend kulcsszó, akkor az a függvény globális függvény.

 

b)

double * Vec2D: csak globális függvénnyel valósítható meg.

class vec2D{
    double x, y;
public:
    vec2D(double x = 0, double y = 0) :x(x), y(y){}
    double getX()const{ return x; }
    double getY()const{ return y; }
};

vec2D operator*(double d, const vec2D &v){
    return vec2D(v.getX()*d, v.getY()*d);
}

 

Ha van Vec2D*double függvényünk, azt is felhasználhatjuk:

A Vec2D*double felhasználásával
class vec2D{
    double x, y;
public:
    vec2D(double x = 0, double y = 0) :x(x), y(y){}
    double getX()const{ return x; }
    double getY()const{ return y; }
    vec2D operator*(double d)const{ return vec2D(x*d, y*d); }
};

vec2D operator*(double d, const vec2D &v){
    return v*d;
}

 

Természetesen a double*Vec2D is megvalósítható friend-del. Ha akarod, próbáld ki. (Freind használata továbbra sem javasolt. Miért? Mert ha módosítunk az osztály bels felépítésén, ezekhez a függvényekhez is hozzá kell nyúlni. Ha macerásabb vagy lehetetlen lenne friend nélkül megvalósítani, akkor természetesen haználhatjuk, ZH-ban is megengedett.)

1. feladat

Készíts float értékeket tároló Verem osztályt! A verem egy olyan adattároló, amelybe a push függvénnyel tudunk új értéket betenni, a pop függvénnyel pedig kivenni. Mindig az utoljára betett értéket tudjuk kivenni, azaz az egymást követ pop hÍvások fordított sorrendben adják az értékeket, mint ahogy a push-sal betettük.

Legyen:

- alapértelmezett konstruktor

- destruktor

- másoló konstruktor

- = operátor

- push függvény:

#include <cstdio>
#include <cstdlib>
#include <stdexcept>

class Verem {
    float *t;
    int n;
public:
    Verem() :t{ nullptr }, n{ 0 } {}
    ~Verem() { delete[]t; }
    Verem(const Verem & v) :t{ nullptr } {
        *this = v;
    }
    Verem & operator=(const Verem & v) {
        if (this == &v)
            return *this;
        delete[]t;
        n = v.n;
        t = new float[n];
        for (int i = 0; i < n; i++)
            t[i] = v.t[i];
        return *this;
    }
    void push(float uj) {
        float *temp = new float[n + 1];
        for (int i = 0; i < n; i++)
            temp[i] = t[i];
        temp[n] = uj;
        n++;
        delete[]t;
        t = temp;
    }
    float pop() {
        if (n == 0)
            throw std::domain_error("Ures verembol probaltal kivenni");
        float *temp = new float[n - 1];
        for (int i = 0; i < n - 1; i++)
            temp[i] = t[i];
        n--;
        float ki = t[n];
        delete[]t;
        t = temp;
        return ki;
    }
};

int main() {
    try {
        Verem v;

        v.push(2);
        v.push(9);
        v.push(-3.1f);

        // Verem w{ v };
        Verem w = v, z;

        v.push(3.14f);
        v = v;
        z = (w = v);

        for (int i = 0; i < 3; i++)
            printf("%g\n", v.pop());
    }
    catch (const std::domain_error & h) {
        printf("%s\n", h.what());
    }
    return 0;
}

2. feladat

Készíts dinamikusan nyúló tömb, azaz vektor osztályt valós számok tárolására! Ahol szükséges, végezz hibakezelést! A hatékonyabb m ködés érdekében kiegészítheted további függvényekkel. Készítend :

- alapértelmezett konstruktor

- destruktor

- másoló konstruktor

- = operátor

- [] operátor 2 változatban: konstans és nem konstans

- push_back függvény: a paraméterként átvett értéket a tömb végéhez f zi (megnöveli a tömb méretét, és az új helyre beteszi az új elemet)

- globális print(vektor) függvény

- globális first(v,n) függvény: a v vektor els n elemét teszi az új vektorba, ezt adja vissza.

Próbáld meg önállóan is lekódolni, és azt küldd be óai munkaként.

Gyakorló feladat

Készíts sztring osztályt! Legyen

- alapértelmezett konstruktor

- destruktor

- másoló konstruktor (hívja meg az = operátort)

- = operátor

- [] operátor 2 változatban: konstans és nem konstans

- összef zés + operátorral

- karakter és C sztring és sztring objektum hozzáf zés += operátorral

- globális print(sztring) függvény

Órai feladatok mintamegoldása

2. feladat: vektor osztály
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <stdexcept>

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

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;
}

void print(const vektor &v){
    printf("(");
    for (int i = 0; i < v.getSize()-1; i++)
        printf("%g, ", v[i]);
    if (v.getSize()>0)printf("%g", v[v.getSize() - 1]);
    printf(")\n");
}

vektor first(const vektor &v, int n){
    vektor uj;
    for (int i = 0; i < n; i++)
        uj.push_back(v[i]);
    return uj;
}

/*

// Hat konyabb v ltozat a first f ggv nyre

void vektor::resize(int ujmeret){
    if (ujmeret < 0)throw std::domain_error("vektor::operator[]: ujmeret < 0");
    double *p=new double[ujmeret];
    const int eddig = ujmeret < n ? ujmeret : n;
    for (int i = 0; i < eddig; i++)
        p[i] = t[i];
    n = ujmeret;
    delete[]t;
    t = p;
}

vektor first(const vektor &v, int n){
    vektor uj;
    uj.resize(n);
    for (int i = 0; i < n; i++)
        uj[i] = v[i];
    return uj;
}
*/


int main(){
    vektor v, v2;
    for (int i = 0; i < 10; i++)
        v.push_back(i+1);
    print(v);
    v2 = v;
    print(v2);
    v = first(v, 5);
    print(v);
    return 0;
}