Klase i objekti u C++-u

Lekcija 16 od 18 · C++

Klasa spaja podatke i funkcije koje rade sa njima u jednu celinu – kao šablon po kome se prave objekti. U ovoj lekciji su atributi i metode, konstruktori, javni i privatni delovi (enkapsulacija) i preklapanje operatora, na primeru razlomka i bankovnog računa.

Pre nego što počneš: potrebno predznanje – STL, strukture.
Kako da učiš: svaki primer prekucaj i pokreni, a zadatke na kraju prvo reši sam/a; uputstvo i rešenje otvori tek posle toga. Svi programi su u C++-u (C++17) i provereno se prevode i daju navedeni izlaz.

Od strukture do klase

Struktura (struct) grupiše podatke – vidi Strukture i unije. Klasa (class) im dodaje metode i kontrolu pristupa. Jedina razlika ključnih reči: u struct je sve podrazumevano public, a u class private.

#include <iostream>
#include <string>
using namespace std;

class Pravougaonik {
public:                                  // dostupno svima
    double a, b;                         // atributi (podaci)

    double povrsina() const {            // metoda; const = ne menja objekat
        return a * b;
    }
    double obim() const {
        return 2 * (a + b);
    }
};

int main() {
    Pravougaonik p;                      // objekat klase Pravougaonik
    cin >> p.a >> p.b;
    cout << "P = " << p.povrsina() << ", O = " << p.obim() << "\n";
    return 0;
}

Konstruktori i enkapsulacija

Konstruktor je posebna metoda istog imena kao klasa; poziva se pri pravljenju objekta i postavlja početno stanje. Podaci koji ne smeju da se menjaju spolja idu u private – menjaju se samo preko metoda koje proveravaju pravila. To se zove enkapsulacija.

#include <iostream>
#include <string>
using namespace std;

class Racun {
private:
    string vlasnik;
    long long stanje;                    // ne može se promeniti direktno spolja

public:
    Racun(string ime, long long pocetno) : vlasnik(ime), stanje(pocetno) {}   // konstruktor

    void uplati(long long iznos) {
        if (iznos > 0) stanje += iznos;
    }
    bool isplati(long long iznos) {      // vraća da li je uspelo
        if (iznos <= 0 || iznos > stanje) return false;
        stanje -= iznos;
        return true;
    }
    long long getStanje() const { return stanje; }
    string getVlasnik() const { return vlasnik; }
};

int main() {
    Racun r("Ana", 1000);
    int q;
    cin >> q;
    while (q--) {
        string op;
        long long x;
        cin >> op >> x;
        if (op == "uplata") r.uplati(x);
        else if (!r.isplati(x)) cout << "odbijeno: " << x << "\n";
    }
    cout << r.getVlasnik() << " ima " << r.getStanje() << "\n";
    // r.stanje = 1000000;   // GREŠKA pri prevođenju: stanje je private
    return 0;
}

Zapis : vlasnik(ime), stanje(pocetno) je lista inicijalizacije – preporučen način da konstruktor postavi atribute. Metode koje samo čitaju označavaju se sa const.

Preklapanje operatora: klasa Razlomak

#include <iostream>
#include <numeric>          // gcd
using namespace std;

class Razlomak {
    long long b, i;          // brojilac, imenilac (private po podrazumevanju)

    void skrati() {
        long long g = gcd(b, i);
        b /= g; i /= g;
        if (i < 0) { b = -b; i = -i; }   // imenilac uvek pozitivan
    }

public:
    Razlomak(long long br = 0, long long im = 1) : b(br), i(im) { skrati(); }

    Razlomak operator+(const Razlomak& o) const { return Razlomak(b * o.i + o.b * i, i * o.i); }
    Razlomak operator*(const Razlomak& o) const { return Razlomak(b * o.b, i * o.i); }
    bool operator<(const Razlomak& o) const { return b * o.i < o.b * i; }

    friend ostream& operator<<(ostream& out, const Razlomak& r) {   // ispis sa cout <<
        return out << r.b << "/" << r.i;
    }
};

int main() {
    long long a, b, c, d;
    cin >> a >> b >> c >> d;
    Razlomak x(a, b), y(c, d);
    cout << x << " + " << y << " = " << x + y << "\n";
    cout << x << " * " << y << " = " << x * y << "\n";
    cout << (x < y ? "prvi je manji" : "prvi nije manji") << "\n";
    return 0;
}

Kada klasa ima operator<, objekti mogu da se sortiraju sa sort i čuvaju u set-u bez posebnog komparatora. Funkcija gcd je iz zaglavlja <numeric> (C++17).

Vektor objekata

#include <bits/stdc++.h>
using namespace std;

class Ucenik {
public:
    string ime;
    vector<int> ocene;

    Ucenik(string i) : ime(i) {}

    double prosek() const {
        if (ocene.empty()) return 0;
        return accumulate(ocene.begin(), ocene.end(), 0.0) / ocene.size();
    }
};

int main() {
    int n;
    cin >> n;
    vector<Ucenik> razred;
    for (int k = 0; k < n; k++) {
        string ime;
        int m;
        cin >> ime >> m;
        Ucenik u(ime);
        for (int j = 0; j < m; j++) { int o; cin >> o; u.ocene.push_back(o); }
        razred.push_back(u);
    }
    const Ucenik* najbolji = &razred[0];
    for (const auto& u : razred)
        if (u.prosek() > najbolji->prosek()) najbolji = &u;
    cout << fixed << setprecision(2) << najbolji->ime << " " << najbolji->prosek() << "\n";
    return 0;
}

Zadaci za vežbu

Za svaki zadatak postoji primer, uputstvo i rešenje. Rešenja su provereno tačna na primerima iz teksta.

ZADATAK 01Težina: lako

Klasa Tacka

Napiši klasu Tacka sa koordinatama x, y, konstruktorom i metodom rastojanje(const Tacka& t). Učitati n tačaka i ispisati obim mnogougla koji one redom čine (zatvoren), na dve decimale.

Primer

Ulaz

4
0 0
3 0
3 4
0 4

Izlaz

14.00
ZADATAK 02Težina: srednje

Štoperica

Napravi klasu Vreme (sati, minuti, sekunde) sa konstruktorom iz ukupnog broja sekundi, operatorom + i ispisom u obliku hh:mm:ss (vodeće nule). Učitati n vremena (hh mm ss) i ispisati njihov zbir; sati mogu preći 24.

Primer

Ulaz

3
01 30 45
00 45 30
10 00 00

Izlaz

12:16:15
Česte greške i saveti
  • Ne zaboravi tačku-zarez posle zatvorene vitičaste zagrade klase: class A { ... };.
  • Ako napišeš sopstveni konstruktor sa parametrima, podrazumevani (bez parametara) više ne postoji – vector<Klasa> v(n) tada ne radi, osim ako parametri imaju podrazumevane vrednosti.
  • Objekte veće od par brojeva prenosi u funkcije kao const Klasa& – bez kopiranja.

Proveri znanje

Otvori kviz

Klase i objekti

1. Šta je podrazumevani pristup članovima u class?




2. Kada se poziva konstruktor?




3. Šta znači const posle metode, npr. double povrsina() const?




4. Šta omogućava operator< u klasi?