Nasleđivanje i polimorfizam u C++-u

Lekcija 17 od 18 · C++

Kada više klasa ima zajedničke osobine, one se izdvajaju u osnovnu klasu, a ostale je nasleđuju i dodaju svoje. Pomoću virtuelnih funkcija isti poziv radi različito za različite vrste objekata – to je polimorfizam.

Pre nego što počneš: potrebno predznanje – klase i objekti.
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.

Osnovna i izvedena klasa

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

class Zivotinja {                         // osnovna klasa
protected:                                // vidljivo u izvedenim klasama, ne spolja
    string ime;
public:
    Zivotinja(string i) : ime(i) {}
    void predstavi() const { cout << "Ja sam " << ime << "\n"; }
};

class Pas : public Zivotinja {            // Pas nasleđuje Zivotinja
public:
    Pas(string i) : Zivotinja(i) {}       // poziv konstruktora osnovne klase
    void laj() const { cout << ime << ": Av!\n"; }
};

int main() {
    Pas p("Reks");
    p.predstavi();                        // nasleđena metoda
    p.laj();                              // sopstvena metoda
    return 0;
}
PristupU klasiU izvedenoj klasiSpolja
publicdadada
protecteddadane
privatedanene

Virtuelne funkcije i polimorfizam

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

class Oblik {
public:
    virtual double povrsina() const = 0;          // čisto virtuelna: svaki oblik MORA da je ima
    virtual string naziv() const = 0;
    virtual ~Oblik() = default;                   // virtuelni destruktor – obavezan uz virtual metode
};

class Krug : public Oblik {
    double r;
public:
    Krug(double r) : r(r) {}
    double povrsina() const override { return M_PI * r * r; }
    string naziv() const override { return "krug"; }
};

class Pravougaonik : public Oblik {
    double a, b;
public:
    Pravougaonik(double a, double b) : a(a), b(b) {}
    double povrsina() const override { return a * b; }
    string naziv() const override { return "pravougaonik"; }
};

class Kvadrat : public Pravougaonik {             // kvadrat je poseban pravougaonik
public:
    Kvadrat(double a) : Pravougaonik(a, a) {}
    string naziv() const override { return "kvadrat"; }
};

int main() {
    int n;
    cin >> n;
    vector<unique_ptr<Oblik>> oblici;             // pokazivači na osnovnu klasu
    for (int i = 0; i < n; i++) {
        string vrsta;
        cin >> vrsta;
        if (vrsta == "K") { double r; cin >> r; oblici.push_back(make_unique<Krug>(r)); }
        else if (vrsta == "P") { double a, b; cin >> a >> b; oblici.push_back(make_unique<Pravougaonik>(a, b)); }
        else { double a; cin >> a; oblici.push_back(make_unique<Kvadrat>(a)); }
    }
    double ukupno = 0;
    cout << fixed << setprecision(2);
    for (const auto& o : oblici) {                // isti poziv, različito ponašanje
        cout << o->naziv() << " " << o->povrsina() << "\n";
        ukupno += o->povrsina();
    }
    cout << "ukupno " << ukupno << "\n";
    return 0;
}
PojamZnačenje
virtualmetoda se bira po stvarnom tipu objekta, ne po tipu pokazivača
= 0čisto virtuelna metoda; klasa sa njom je apstraktna – ne može se napraviti njen objekat
overridekaže prevodiocu da metoda zamenjuje virtuelnu iz osnovne klase – ako se ime ili parametri ne poklapaju, javlja grešku
unique_ptr, make_uniquepametni pokazivač: objekat se sam briše (Pokazivači)

Bez reči virtual poziv o->naziv() bi uvek pozvao verziju iz klase Oblik. Polimorfizam omogućava da se doda nova vrsta oblika (npr. trougao) bez menjanja petlje u main.

Kada koristiti nasleđivanje

OdnosRešenjePrimer
„je vrsta“ (is-a)nasleđivanjeKvadrat je pravougaonik, Pas je životinja
„ima“ (has-a)atribut (kompozicija)Automobil ima motor – Motor motor; unutar klase Automobil

Na takmičenjima se nasleđivanje retko koristi; u igrama, simulacijama i većim programima vrlo često. Isti pojmovi u Javi: Nasleđivanje klasa (Java).

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: srednje

Zaposleni i plate

Osnovna klasa Zaposleni ima ime i virtuelnu metodu plata(). Izvedene: Stalni (fiksna mesečna plata) i Honorarni (broj sati × cena sata). Učitati n zaposlenih (S ime plata ili H ime sati cena) i ispisati svako ime sa platom i ukupan trošak.

Primer

Ulaz

3
S Ana 90000
H Marko 40 1200
S Iva 75000

Izlaz

Ana 90000
Marko 48000
Iva 75000
ukupno 213000
Česte greške i saveti
  • U osnovnoj klasi sa virtuelnim metodama uvek napiši virtual ~Klasa() = default;.
  • Polimorfizam radi samo preko pokazivača ili referenci – vector<Oblik> (bez pokazivača) „iseca“ objekte na osnovni deo.
  • Uz svaku zamenjenu metodu piši override – greške u imenu ili parametrima tada prijavljuje prevodilac.

Proveri znanje

Otvori kviz

Nasleđivanje i polimorfizam

1. Šta je apstraktna klasa?




2. Kome je dostupan protected član?




3. Šta radi reč override?