predavanje07

Download Report

Transcript predavanje07

RP3/predavanje07
 Nasljeđivanje
13/04/2015
---------- Računarski praktikum 3 ---------Maja Starčević
1
Izvedene klase
Klasa može naslijediti drugu klasu, ali samo jednu. S druge
strane, neku klasu može naslijediti više klasa. Sva
nasljeđivanja su javna (tj. “čuvaju sučelja”).
public class C
{
public int x;
}
public class D : C
{
Nasljeđuje varijablu x
public int y;
}
13/04/2015
-------Računarski praktikum 3-------
2
Apstraktne klase
Apstraktna klasa sadrži barem jednu apstraktnu funkciju
(metodu, svojstvo, indekser ili događaj), odnosno funkciju
koja nema implementaciju, već se može implementirati u
izvedenim klasama. Ako sadrži apstraktnu funkciju, nije
implicitno apstraktna, već mora imati modifikator abstract.
U nastavku ćemo govoriti o metodama, ali sve se može
primijeniti i na ostale tipove funkcija koje mogu biti
apstraktne. Sve takve funkcije se mogu nalaziti i u sučeljima.
Razlika je u tome što sučelja ne mogu sadržavati ništa osim
takvih funkcija i one u njima moraju nužno biti
neimplementirane.
13/04/2015
-------Računarski praktikum 3-------
3
Apstraktne klase
Klasa koja se deklarira kao apstraktna ne može se
instancirati. Mogu se instancirati samo njezine konkretne
izvedene klase.
Apstraktna metoda ne može biti označena kao privatna.
Ukoliko nije definirano tijelo metode, ona mora imati jedan
od modifikatora abstract, extern ili partial.
Pri implementaciji metode, koja je apstraktna u baznoj klasi,
moramo navesti modifikator override.
13/04/2015
-------Računarski praktikum 3-------
4
Apstraktne klase
public abstract class BaznaKlasa
{
public abstract void Metoda( );
}
public class IzvedenaKlasa: BaznaKlasa
{
public override void Metoda ( )
{
//implementacija
}
}
13/04/2015
-------Računarski praktikum 3-------
5
Apstraktne klase
Razlike i sličnosti apstraktnih klasa i sučelja:
 oboje sadrže neimplementirane funkcije, sučelja ne
sadrže ništa drugo
 sučelja ne mogu sadržavati konkretne (implementirane)
funkcije, dok apstraktne klase mogu
 klasa može naslijediti više sučelja, ali samo jednu klasu,
bilo apstraktnu ili konkretnu
 modifikatori pristupa kod funkcija sučelja su implicitno
public, dok kod (apstraktnih) funkcija apstraktne klase ne
smiju biti private (dakle treba ih eksplicitno navesti).
13/04/2015
-------Računarski praktikum 3-------
6
Apstraktne klase
Neimplementirana (apstraktna) metoda iz apstraktne klase ne mora
se nužno implementirati u direktno izvedenoj klasi.
abstract class C1
{
int a;
public abstract void f();
}
abstract class C2 : C1
{
int y;
}
class C3 : C2
{
public override void f() { }
}
13/04/2015
-------Računarski praktikum 3-------
7
O modifikatorima pristupa
Kod nadjačavanja virtualne metode ili implementacije
apstraktne metode iz bazne klase (odnosno kad koristimo
modifikator override) ne može se mijenjati modifikator
pristupa (koji ne smije biti privatan).
Kod obične reimplementacije (kad metoda u izvedenoj
skriva metodu istog imena iz bazne klase), to je dozvoljeno.
13/04/2015
-------Računarski praktikum 3-------
8
Virtualne metode
Virtualne metode su metode bazne klase koje omogućuju
polimorfizam. Konkretno, referenca na baznu klasu može
referirati i na objekt bazne klase i na objekt iz nje izvedene
klase.
Metoda koja ima modifikator virtual može biti nadjačana od
strane bilo koje izvedene klase. Pritom se poziva metoda
ovisno o tipu objekta (bazni ili izvedeni), a ne o tipu
reference (koja može u oba slučaja biti referenca na bazni
tip).
Virtualna metoda je implementirana metoda, za razliku od
apstraktne. Ne mora nužno biti nadjačana.
13/04/2015
-------Računarski praktikum 3-------
9
Virtualne metode
Pri nadjačavanju metode u izvedenoj klasi koristimo ključnu
riječ override.
Svojstva, događaji i indekseri također mogu imati modifikator
virtual.
Ukoliko je metoda redefinirana u izvedenoj klasi, onda
kažemo da metoda u izvedenoj klasi skriva metodu istog
imena iz bazne klase. Pritom redefinirana metoda mora biti
označena s new, u protivnom kompilator daje upozorenje.
13/04/2015
-------Računarski praktikum 3-------
10
Virtualne metode
public class BaznaKlasa
{
public virtual void Metoda( );
{
//implementacija
}
}
public class IzvedenaKlasa: BaznaKlasa
{
public override void Metoda ( )
{
//nova implementacija
}
}
13/04/2015
-------Računarski praktikum 3-------
11
Virtualne metode
Povratni tip, potpis i pristupačnost virtualne i nadjačane
metode moraju biti jednaki (virtualne metodene mogu biti
privatne).
Nadjačana metoda može pozvati svoju implementaciju iz
temeljne klase pomoću ključne riječi base.
13/04/2015
-------Računarski praktikum 3-------
12
Virtualne metode
class C
{
public virtual void Ispisi()
{
Console.WriteLine("U klasi C");
}
}
class D : C
{
public void Ispisi()
{
Console.WriteLine("U klasi D");
}
}
13/04/2015
-------Računarski praktikum 3-------
Što će se ispisati ako
metodu ne označimo s
override?
13
Virtualne metode
class Program
{
static void Main(string[] args)
{
C c=new C( );
C d=new D( );
c.Ispisi( );
d.Ispisi( );
}
}
13/04/2015
-------Računarski praktikum 3-------
14
Virtualne metode
public class BaznaKlasa
{
virtual public void Metoda()
{
Console.WriteLine("Hello!");
}
}
public class IzvedenaKlasa : BaznaKlasa
{
public override void Metoda( )
{
base.Metoda( );
Console.WriteLine("Hello world!");
}
}
13/04/2015
-------Računarski praktikum 3-------
class Program
{
static void Main( )
{
IzvedenaKlasa izv =
new IzvedenaKlasa( );
izv.Metoda( );
}
}
//Hello!
//Hello world!
15
Zapečaćene klase i metode
Nadjačana funkcija članica može zapečatiti svoju
implementaciju, tj. spriječiti izvedene klase da je opet
nadjačaju. To se postiže uporabom ključne riječi sealed.
public sealed override Metoda ( ) { …}
Može se zapečatiti na analogan način i čitava klasa pri čemu
se sprječava da je druge klase nasljeđuju.
13/04/2015
-------Računarski praktikum 3-------
16
Skrivanje članova
U primjeru
public class A
{ public int x; }
public class B : A { public int x; }
varijabla x u klasi B skriva varijablu x u klasi A. Kompilator će
izbaciti upozorenje. Da bi se to izbjeglo, koristi se modifikator
new:
public class A
{ public int x; }
public class B : A { public new int x; }
13/04/2015
-------Računarski praktikum 3-------
17
Skrivanje metode
public class BaznaKlasa
{
public void Metoda()
{
Console.WriteLine("Hello!");
}
}
public class IzvedenaKlasa : BaznaKlasa
{
public new void Metoda( )
{
base.Metoda( );
Console.WriteLine("Hello world");
}
}
13/04/2015
-------Računarski praktikum 3-------
class Program
{
static void Main( )
{
IzvedenaKlasa izv1=
new IzvedenaKlasa( );
BaznaKlasa izv2=
new IzvedenaKlasa( );
izv1.Metoda( );
izv2.Metoda( );
}
}
//Hello!
Hello world!
Hello!
18
Nadjačavanje metode
public class BaznaKlasa
{
public virtual void Metoda()
{
Console.WriteLine("Hello!");
}
}
public class IzvedenaKlasa : BaznaKlasa
{
public override void Metoda( )
{
base.Metoda( );
Console.WriteLine("Hello again!");
}
}
13/04/2015
-------Računarski praktikum 3-------
class Program
{
static void Main( )
{
IzvedenaKlasa izv1=
new IzvedenaKlasa( );
BaznaKlasa izv2=
new IzvedenaKlasa( );
izv1.Metoda( );
izv2.Metoda( );
}
}
//Hello!
Hello again!
Hello!
Hello again!
19
override - new virtual
Primjer hijerarhije nasljeđivanja
s nadjačavanjem metode:
class A
{
public virtual void Ispisi()
{
Console.WriteLine("U klasi A");
}
}
13/04/2015
class B : A
{
public override void Ispisi()
{
Console.WriteLine("U klasi B");
}
}
class C : B
{
public override void Ispisi()
{
Console.WriteLine("U klasi C");
}
}
-------Računarski praktikum 3-------
20
override - new virtual
class Program
{
static void Main(string[] args)
{
A obj1 = new A();
A obj2 = new B();
A obj3 = new C();
B obj4 = new B();
B obj5 = new C();
C obj6 = new C();
obj1.Ispisi();
obj2.Ispisi();
obj3.Ispisi();
obj4.Ispisi();
obj5.Ispisi();
obj6.Ispisi();
}
}
// A B C B C C
13/04/2015
-------Računarski praktikum 3-------
21
override - new virtual
Pretpostavimo da je dizajnerklase B samo korisnik klase A
te da je u klasi B definirao virtualnu metodu Ispisi.
Naknadno je u klasu A dodana virtualna metoda jednakog
imena.
Da bi metoda nadjačala virtualnu iz temeljne klase, mora biti
označena s override. Ukoliko je opet označena s virtual,
spriječili smo nadjačavanje. Kompilator javlja upozorenje
koje se može spriječiti dodavanjem ključne riječi new.
13/04/2015
-------Računarski praktikum 3-------
22
override - new virtual
Sad spuštamo početak
lanca nadjačavanja:
class A
{
public virtual void Ispisi()
{
Console.WriteLine("U klasi A");
}
}
class B : A
{
public new virtual void Ispisi()
{
Console.WriteLine("U klasi B");
}
}
class C : B
{
public override void Ispisi()
{
Console.WriteLine("U klasi C");
}
}
// Test ispisuje A A A B C C
13/04/2015
-------Računarski praktikum 3-------
23
“abstract = virtual”
class Program
{
static void Main(string[] args)
{
public abstract class A
{
public abstract void f();
}
C c = new C();
D d = new D();
c.f();
d.f();
B bc = c;
B bd = d;
bc.f();
bd.f();
public class B : A
{
public override void f() { Console.WriteLine("B"); }
}
public class C : B
{
public override void f() { Console.WriteLine("C"); }
}
}
public class D : B
{
public new void f() { Console.WriteLine("D"); }
}
13/04/2015
}
-------Računarski praktikum 3-------
24
“abstract = virtual”
Prethodni Main ispisuje C, D, C, B.
Dakle, apstraktna metoda je implicitno virtualna metoda.
Drugim riječima, dokle god (re)implementaciju te metode u
izvedenim klasama označavamo s override, poštuje se
virtualni mehanizam, odnosno dolazi do dinamičkog
povezivanja.
13/04/2015
-------Računarski praktikum 3-------
25
Ponavljanje
class A { public virtual void g(){ Console.Write("A"); } }
class B : A { public sealed override void g() { Console.Write("B"); } }
class C : B { public new virtual void g() { Console.Write("C"); } }
class D : C { public new virtual void g() { Console.Write("D"); } }
class E : D { public override void g() { Console.Write("E"); } }
class F : E { public new void g() { Console.Write("F"); } }
class Program
{
static void Main(string[] args)
{
F f = new F();
A a = f; B b = f; C c = f; D d = f; E e = f;
a.g(); b.g(); c.g(); d.g(); e.g(); f.g();
}
}
13/04/2015
-------Računarski praktikum 3-------
26
Ponavljanje
class A { public virtual void g(){ Console.Write("A"); } }
class B : A { public sealed override void g() { Console.Write("B"); } }
class C : B { public new virtual void g() { Console.Write("C"); } }
class D : C { public new virtual void g() { Console.Write("D"); } }
class E : D { public override void g() { Console.Write("E"); } }
class F : E { public new void g() { Console.Write("F"); } }
class Program
{
static void Main(string[] args)
{
F f = new F();
A a = f; B b = f; C c = f; D d = f; E e = f;
a.g(); b.g(); c.g(); d.g(); e.g(); f.g();
}
}
13/04/2015
-------Računarski praktikum 3-------
BBCEEF
27
base
Ključna riječ base koristi se i za pozivanje konstruktora
bazne klase.
Uvijek se mora pozvati konstruktor iz bazne klase koji će
inicijalizirati varijable članice bazne klase. Ukoliko se ne
pozove eksplicitno s base, onda će kompilator pozvati
defaultni konstruktor iz bazne klase i naravno javiti grešku
ukoliko nije definiran.
13/04/2015
-------Računarski praktikum 3-------
28
base
public class BaseClass
{
public int x;
public BaseClass (int x){this.x=x;}
}
public class SubClass : BaseClass
{
public SubClass (int x) : base (x) { }
}
13/04/2015
-------Računarski praktikum 3-------
29
base
class C
{
int x;
public C(int a) { x = a; }
}
class D : C
{
int y;
public D(int a) { y = a; }
}
13/04/2015
// greška – bazna klasa ne
definira konstruktor bez
parametara
-------Računarski praktikum 3-------
30
base
class C
{
int x;
public C(int a) { x = a; }
}
class D: C
{
int y;
public D(int a) : base(0) { y = a; }
}
13/04/2015
-------Računarski praktikum 3-------
31
Kastanje
Kastanjem prema gore (engl. upcasting) kreiramo referencu
na baznu klasu pomoću reference izvedene klase.
class A
{
public int p1;
}
Varijabla a i dalje pokazuje na isti
objekt tipa B.
Console.WriteLine(a==b);
class B : A
{
public int p2;
}
....
B b=new B( );
A a=b;
//upcast
13/04/2015
// True
a ima restriktivniji pogled na isti objekt.
Console.WriteLine(a.p1); // u redu
Console.WriteLine(a.p2); // greška
Računarski praktikum 3
32
Kastanje
Kastanjem prema dolje (engl downcasting) se stvara
referenca na izvedenu klasu iz reference bazne klase.
B b=new B( );
A a=b;
B c=(B)a;
//upcast
//downcast
---------------------------------------------------------class D : A { }
D d=new D( );
A e=d;
B f=(B)e;
13/04/2015
//ok
// baca InvalidCastException iznimku
Računarski praktikum 3
33
Kastanje
As operator vrši kastanje prema dolje, ali vraća null ako taj
postupak ne uspije. Prethodni primjer na taj način daje:
B f=e as B;
// f je null
Is operator samo provjerava može li to kastanje uopće
uspjeti:
if (e is B)
{
......
}
13/04/2015
Računarski praktikum 3
34
Kastanje
Ako imamo definiranu klasu C koja ne nasljeđuje A, onda
se varijabli cc definiranoj s
C cc=e as B;
ne pridružuje null, već kompilator javlja grešku. Operator is se
može i dalje koristiti.
Napomena: operatori as i is mogu se koristiti i pri kastanju u
sučelje kao što se vidi iz sljedećeg primjera.
13/04/2015
Računarski praktikum 3
35
Kastanje
public interface ICitljivo
{
void Citaj( );
}
class C : ICitljivo
{
public void Citaj( ){ … }
}
class Program
{
static void Main(string[] args)
{
C c=new C( );
D d = new D( );
ICitljivo o1 = c as ICitljivo;
ICitljivo o2 = d as ICitljivo;
Console.WriteLine("{0}, {1}",
o1 == null, o2 == null);
if (c is ICitljivo)
Console.WriteLine("c je citljiv");
class D
{
public void Citaj( ) { …. }
}
}
}
13/04/2015
Računarski praktikum 3
// False, True
// c je citljiv
36