Nasleđivanje klasa
Uvod:
Nakon što smo se upoznali sa osnovnim članovima klase – podacima, funkcijama i objektima – sledeći važan koncept u objektno orijentisanom programiranju (OOP) je nasleđivanje klasa. Nasleđivanje omogućava stvaranje novih klasa koje preuzimaju (nasleđuju) osobine i ponašanje već postojećih klasa, uz mogućnost proširivanja ili modifikovanja tih osobina.
Pojam nasleđivanja:
Nasleđivanje je mehanizam u OOP-u koji omogućava da jedna klasa preuzme (nasledi) osobine i ponašanje druge klase. Klasa koja nasleđuje naziva se izvedena klasa, dok je klasa koja se nasleđuje bazna klasa (ili roditeljska klasa).
- Bazna (nadređena) klasa – klasa čije se osobine i metode nasleđuju.
- Izvedena (potomak) klasa – klasa koja nasleđuje osobine i metode od bazne klase, a može dodavati i svoje sopstvene.
Primer iz stvarnog života:
Zamislite da imate klasu Vozilo koja definiše osnovne osobine svih vozila, kao što su brzina i boja. Zatim, možete kreirati dve izvedene klase: Automobil i Bicikl. Obe izvedene klase nasleđuju osnovne osobine iz klase Vozilo, ali mogu imati i dodatne specifične osobine i metode.
Kako funkcioniše nasleđivanje?
Izvedena klasa automatski preuzima sve osobine i metode iz nadređene klase. To znači da sve funkcionalnosti iz bazne klase postaju dostupne u izvedenoj klasi, ali izvedena klasa može dodavati nove ili menjati postojeće metode.
Sintaksa nasleđivanja
Da bi izvedena klasa nasleđivala baznu klasu, koristi se dvotačka :.
class Vozilo {
public int brzina;
public void Pokreni() {
Console.WriteLine("Vozilo se kreće.");
}
}
class Auto : Vozilo { // Klasa Auto nasleđuje klasu Vozilo
public int brojVrata;
}
Pažnja: U C# se podrazumeva da se prvo poziva konstruktor roditeljske klase - zato ne vidite da se poziva, kao što je slučaj kod JavaScripta. Ako konstruktor ne postoji, kompajler će kreirati podrazumevani konstruktor bez parametara...
Ovde se koristi ključna reč extends kako bi klasa Auto nasledila klasu Vozilo. Funkcija super() poziva konstruktor bazne klase, omogućavajući pristup njenim članovima, kao što je brzina.
class Vozilo {
constructor() {
this.brzina = 0; // Podatak - član
}
// Funkcija članica
Pokreni() {
console.log("Vozilo se kreće.");
}
}
class Auto extends Vozilo { // Klasa Auto nasleđuje klasu Vozilo
constructor() {
super(); // Pozivanje konstruktora bazne klase (Vozilo)
this.brojVrata = 0; // Podatak - član specifičan za klasu Auto
}
}
U ovom primeru, klasa Auto nasleđuje klasu Vozilo. To znači da svi podaci i funkcije iz klase Vozilo postaju dostupni u klasi Auto.
Korišćenje nasleđenih članova:
Instanca klase Auto sada može koristiti članove klase Vozilo, kao i sopstvene članove.
Auto mojAuto = new Auto(); mojAuto.brzina = 100; // Nasleđeni član iz klase Vozilo mojAuto.brojVrata = 4; // Član klase Auto mojAuto.Pokreni(); // Nasleđena metoda
const mojAuto = new Auto();
mojAuto.brzina = 100;
mojAuto.brojVrata = 4;
mojAuto.Pokreni(); // Ispisuje: "Vozilo se kreće."
console.log(`Broj vrata: ${mojAuto.brojVrata}`);
console.log(`Brzina: ${mojAuto.brzina}`);
Ovde smo kreirali instancu klase Auto, dodelili vrednosti za članove brzina i brojVrata, a zatim pozvali nasleđenu funkciju članicu Pokreni iz klase Vozilo.
Proširenje funkcionalnosti:
Nasleđivanje ne samo da omogućava preuzimanje postojećih članova klase, već i dodavanje novih članova u izvedenoj klasi.
class Auto : Vozilo {
public int brojVrata;
public void PrikaziPodatke() {
Console.WriteLine("Broj vrata: " + brojVrata);
Console.WriteLine("Brzina: " + brzina);
}
}
class Auto extends Vozilo { // Klasa Auto nasleđuje klasu Vozilo
constructor() {
super(); // Pozivanje konstruktora bazne klase (Vozilo)
this.brojVrata = 0; // Podatak - član specifičan za klasu Auto
}
// Funkcija za prikaz podataka specifična za Auto
PrikaziPodatke() {
console.log(`Broj vrata: ${this.brojVrata}`);
}
}
Ovde smo u klasi Auto dodali novu metodu PrikaziPodatke, koja kombinuje podatke iz klase Auto i Vozilo.
Overriding (redefinisanje metoda):
Izvedena klasa može promeniti ponašanje metode iz bazne klase korišćenjem ključne reči override. Ovo je korisno kada želimo da izvedena klasa ponašanje nasleđene metode prilagodi svojim specifičnostima.
Primer redefinisanja metode:
class Vozilo {
public virtual void Pokreni() {
Console.WriteLine("Vozilo se pokreće.");
}
}
class Auto : Vozilo {
public override void Pokreni() {
Console.WriteLine("Auto se pokreće.");
}
}
class Vozilo {
// Metoda Pokreni u bazičnoj klasi
Pokreni() {
console.log("Vozilo se pokreće.");
}
}
class Auto extends Vozilo {
// Overriding metode Pokreni u izvedenoj klasi
Pokreni() {
console.log("Auto se pokreće.");
}
}
// Kreiramo instance
const mojeVozilo = new Vozilo();
const mojAuto = new Auto();
// Pozivanje metode
mojeVozilo.Pokreni(); // Ispisuje: "Vozilo se pokreće."
mojAuto.Pokreni(); // Ispisuje: "Auto se pokreće."
Sada, ako pozovemo metodu Pokreni na instanci klase Auto, biće pozvana redefinisana verzija iz klase Auto, dok će za instancu klase Vozilo biti pozvana originalna verzija.
i
using System;
class Vozilo
{
public int brzina; // Podatak - član
// Konstruktor
public Vozilo()
{
brzina = 0;
}
// Funkcija članica
public void Pokreni()
{
Console.WriteLine("Vozilo se kreće.");
}
// Funkcija za prikaz podataka
public virtual void PrikaziPodatke()
{
Console.WriteLine($"Brzina: {brzina}");
}
}
class Auto : Vozilo // Klasa Auto nasleđuje klasu Vozilo
{
public int brojVrata; // Podatak - član specifičan za klasu Auto
// Konstruktor
public Auto() : base() // Pozivanje konstruktora bazne klase (Vozilo)
{
brojVrata = 0;
}
// Funkcija za prikaz podataka specifična za Auto
public override void PrikaziPodatke()
{
base.PrikaziPodatke(); // Poziv funkcije iz bazne klase (Vozilo)
Console.WriteLine($"Broj vrata: {brojVrata}");
}
}
// Kreiranje instance klase Auto
class Program
{
static void Main()
{
Auto mojAuto = new Auto();
mojAuto.brzina = 100;
mojAuto.brojVrata = 4;
// Pozivanje funkcija
mojAuto.Pokreni(); // Ispisuje: "Vozilo se kreće."
mojAuto.PrikaziPodatke(); // Ispisuje: "Brzina: 100", "Broj vrata: 4"
}
}
U ovom C# kodu:
- Koristi se ključna reč
baseza pozivanje konstruktora i metoda iz bazne klase. - Ključna reč
virtualkoristi se u bazičnoj klasi za funkciju koju želimo redefinisati, dokoverrideoznačava redefinisanje te funkcije u izvedenoj klasi.
class Vozilo {
constructor() {
this.brzina = 0; // Podatak - član
}
// Funkcija članica
Pokreni() {
console.log("Vozilo se kreće.");
}
// Funkcija za prikaz podataka
PrikaziPodatke() {
console.log(`Brzina: ${this.brzina}`);
}
}
class Auto extends Vozilo { // Klasa Auto nasleđuje klasu Vozilo
constructor() {
super(); // Pozivanje konstruktora bazne klase (Vozilo)
this.brojVrata = 0; // Podatak - član specifičan za klasu Auto
}
// Funkcija za prikaz podataka specifična za Auto
PrikaziPodatke() {
super.PrikaziPodatke(); // Poziv funkcije iz bazne klase (Vozilo)
console.log(`Broj vrata: ${this.brojVrata}`);
}
}
// Kreiranje instance klase Auto
const mojAuto = new Auto();
mojAuto.brzina = 100;
mojAuto.brojVrata = 4;
// Pozivanje funkcija
mojAuto.Pokreni(); // Ispisuje: "Vozilo se kreće."
mojAuto.PrikaziPodatke(); // Ispisuje: "Brzina: 100", "Broj vrata: 4"
U ovoj verziji:
- Funkcija članica PrikaziPodatke je dodata u obe klase.
- U klasi Vozilo, funkcija PrikaziPodatke prikazuje brzinu.
- U klasi Auto, funkcija PrikaziPodatke prvo poziva funkciju iz bazne klase pomoću
super.PrikaziPodatke(), a zatim ispisuje specifični podatak klase Auto, broj vrata.
Pozivanjem mojAuto.PrikaziPodatke(), dobijamo sve informacije o objektu, uključujući i nasleđene podatke.
Zamislimo da pravimo online prodavnicu i imamo klasu Proizvod koja sadrži osnovne informacije o proizvodima, kao što su cena i opis. Sada želimo da napravimo posebne tipove proizvoda, kao što su ElektronskiProizvod i Knjiga.
Klasa Proizvod (Bazna klasa): - cena - opis - prikaziDetalje() Klasa ElektronskiProizvod (Izvedena klasa): - nasleđuje cena, opis - ima dodatno polje: garancija - ima dodatnu metodu: prikaziGaranciju() Klasa Knjiga (Izvedena klasa): - nasleđuje cena, opis - ima dodatno polje: autor - ima dodatnu metodu: prikaziAutora()
Bazna klasa – Proizvod
class Proizvod {
// Podaci-članovi (atributi)
cena;
opis;
// Funkcija članica (metoda)
prikaziDetalje() {
// Kod za prikazivanje osnovnih informacija o proizvodu
}
}
Izvedena klasa – ElektronskiProizvod
class ElektronskiProizvod extends Proizvod {
// Dodatni podaci-članovi
garancija;
// Dodatna metoda
prikaziGaranciju() {
// Kod za prikazivanje informacija o garanciji
}
}
Izvedena klasa – Knjiga
class Knjiga extends Proizvod {
// Dodatni podaci-članovi
autor;
// Dodatna metoda
prikaziAutora() {
// Kod za prikazivanje imena autora
}
}
U ovom primeru, ElektronskiProizvod i Knjiga nasleđuju osobine i metode iz klase Proizvod (kao što su cena i prikaziDetalje()), ali imaju i dodatne osobine specifične za te proizvode.
4. Prednosti nasleđivanja
-
Ponovna upotreba koda: Umesto da pišemo iste metode više puta za različite klase, možemo ih definisati u baznoj klasi i nasleđivati u izvedenim klasama. Jednom napisani kod u baznoj klasi može se koristiti u mnogo izvedenih klasa.
-
Proširenje funkcionalnosti: Izvedena klasa može imati dodatne metode ili podatke koji su specifični samo za tu klasu. Tako dobijamo fleksibilnost u definisanju različitih tipova objekata.
-
Održavanje koda: Ako želimo da promenimo neki deo koda, dovoljno je promeniti ga u baznoj klasi, i sve izvedene klase će automatski preuzeti te promene.
Zadaci:
- Osmisliti baznu klasu Zaposleni, sa podacima-članovima kao što su ime i plata, i metodama kao što su prikaziInformacije().
- Kreirati izvedene klase Menadžer i Programer koje nasleđuju klasu Zaposleni, ali dodaju dodatne osobine (npr. tim za menadžera ili programski jezici za programera).
- Napisati kod koji prikazuje informacije o svakom zaposlenom, koristeći nasleđivanje.
Ključni pojmovi:
- Bazna klasa (nadređena klasa) – klasa iz koje se nasleđuju osobine i metode.
- Izvedena klasa (potomak) – klasa koja nasleđuje sve osobine i metode bazne klase, ali može imati i dodatne funkcionalnosti.
- Nasleđivanje – mehanizam u OOP-u koji omogućava jednoj klasi da nasledi osobine druge klase.