Osztályok
Osztályokat a class utasítással definiálhatunk. CA-VO -ban is három láthatósági szint van az egyes tagokra:
- hidden - az osztály saját tagjai, amiket csak ő lát
- protect - a származtatott osztályok is látják
- export - kívülről is látszik
Van még egy negyedik is, az
instance, ami önmagában ugyanaz mint a
protect, viszont az elérése lassabb. Még egy különbség, hogy más
módon viselkedik az úgynevezett
access és
assign metódusokkal. Az ilyen
instance -oknak is külön lehet láthatósága
a fentiek közül (pl.
hidden instance).
Az osztályok metódusait nem az osztály törzsében deklaráljuk/definiáljuk, hanem külön, a metódus után írva az osztály nevét. Ha viszont erősen típusos
a metódusunk, akkor az osztályban is deklarálni kell (csak a nevét). Metódusok láthatóságát nem lehet megadni.
A konstruktornak nagyjából megfelel az
Init metódus, a destruktornak pedig az
Axit() (Exit???). Mivel van automatikus szemétgyűjtés ezért nem kötelező ezeket megadni.
Ha egy osztály statikus, akkor csak az adott modulban látszik. Természetesen metódusokra is működik az
export local.
class Apple
hidden Meret as int
export Szin as int
declare method Init
method Init(m as int, sz as int) class Apple
Meret := m
Szin := sz
return self
Az
access és az
assign metódusok nagyon hasonlítanak a C#-os propertykre (get/set). Előbbivel egy nem exportált member értékét lehet elkérni,
az utóbbival pedig értékadás operátor segítségével megváltoztatni.
assign metódusoknál érdemes visszaadni a változó értékét, hogy lehessen értékadás láncokat csinálni.
Mostantól a/a metódusoknak fogom hívni ezeket, mert egyszerűbb leírni.
class Apple
hidden instance meret as int
access meret class Apple
return meret
assign meret(m) class Apple
meret := m
return meret
function Start()
local a as Apple
a := Apple{}
a:meret := 15 // ez az assign
? a:meret // ez meg az access
_Accept("")
return nil
Az
instance változók pont az ilyen esetekre lettek kitalálva. Amikor egy ilyen a/a metódust ugyanazzal a névvel definiálunk mint az
instance változót,
akkor onnantól kezdve minden hivatkozás arra a névre (akár külső akár belső) a metódust fogja meghívni, persze kivéve az a/a metóduson belül mert az úgy fura lenne.
Amennyiben az a/a metódust nem
instance változóval használjuk, akkor az osztályon belüli hivatkozások nem a metódust fogják hivni, hanem közvetlenül a változót.
Egy érdekes fogalom a
virtuális változó, ami olyan változót akar jelenteni, ami nincsen explicit módon definiálva az osztályban, hanem ilyen a/a metódusokkal
pakolgatjuk össze. Ha az osztályon belülről akarunk hivatkozni egy ilyen változóra, akkor a
self: prefixet elé kell írni (hasonlóan akkor is, ha egy nem
instance -os a/a metódust akarunk meghívni).
class Apple
hidden meret as int
access nincsisilyen class Apple
return meret + 3
assign nincsisilyen(m) class Apple
meret := m - 3
return meret
Azt mondjuk, hogy egy változó
korán köt, hogy ha a változó helye a memóriában fordítási időben már ismert, így a fordító tud kódot generálni hozzá.
Ennek az ellentéte a
későn kötés, amikor nem tudjuk a helyet, ilyenkor futási időben keresi ki egy táblából. Előbbieket érdemesebb használni, gyorsabb lesz tőle
az alkalmazás.
láthatóság |
kötés |
export |
korán, ha lehet |
instance |
mindig későn |
hidden |
mindig korán |
protect |
mindig korán |
Így már érthető, hogy az
instance miért lasabb mint a
protect.
Objektumok
Struktúráknál volt olyan, hogy is. Na az itt nem megengedett, az objektumokat a szemétgyűjtő kezeli. Az objektumot úgy hozzuk létre, mintha
egy metódust hívnánk, de () helyett {} -ek közé kell tenni az argumentumokat. Ha van az osztálynak Init metódusa, akkor az fog meghívódni, ha nincs akkor a default.
Az objektum tagjaira a : operátorral hivatkozhatunk.
function Start(p)
local a as Apple
a := Apple{10, 2}
? a:Szin
_Accept("")
return nil
Minden objektum a beépített
object típusból származik.
Öröklődés
Származtatni az inherit kulcsszóval lehet.
A származtatott osztály örökli az ősosztály minden tagját és minden metódusát, viszont az ősosztály hidden dolgai nem lesznek láthatóak a származtatottban.
class Gyumolcs
protect Meret as int
export Szin as int
class Apple inherit Gyumolcs
declare method Init
Többszörös öröklődés nincs.
Polimorfizmus, dinamikus kötés
Metódusokat szerencsére felül lehet definiálni. Mivel az objektum változó nagyon olyan mint egy pointer, ezért mindig a származtatott osztály
metódusa fog meghívódni.
class Base
class Derived inherit Base
method foo class Base
? "base::foo"
method foo class Derived
? "Derived::foo"
function Start()
local p as Base
p := Derived{}
p:foo()
_Accept("")
return nil
Interfészek
Úgy tűnik nincs...