Az Octave lehetőséget ad osztályok definiálására, valamint operátorok és függvények túlterhelésére. Az osztályok segítségével enkapszuláció valósítható meg, kivédhető az, hogy az osztályhoz tartozó adatokat véletlenül változtassák meg.
A nyelvi eszközök leírása során példaként egy
polinomot reprezentáló osztály fog szerepelni. A
polinomot a
vektorral fogjuk reprezentálni.
Minden osztálynak külön könyvtárat kell létrehozni, melynek
neve az osztály neve, előtte a @ szimbólummal. Ebbe a
könyvtárba kell helyezni az osztály függvényeit. Köztük
a konstruktort is, melynek segítségével létrehozhatunk
egy példányt az osztályból. Például esetünkben
a @polynomial/polynomial.m fájl tartalma
lehetne:
Ahogy a példa mutatja, a konstruktor visszatérési értéke a class függvény eredménye kell, hogy legyen. Ennek a függvénynek két paramétere van: az első az adattagokkal inicializált struktúra, a második pedig az osztály neve. A konstruktor hívására egy példa:
Az argumentumként függvényt váró beépített függvények ugyanúgy alkalmazhatóak az így létrehozott osztályokhoz tartozó függvényekre is. Például a help @polynomial/display parancs kiírja a polynomial osztály display függvényéhez tartozó dokumentációt, a type @polynomial/display parancs a függvény kódját, a dbstop @polynomial/display pedig a függvény első végrehajtható sorához beszúr egy töréspontot a debugger számára.
Annak ellenőrzése, hogy egy változó egy bizonyos osztály példánya-e, az isobject és isa függvények használhatóak:
További hasznos általános, osztályokkal kapcsolatos függvények:
methods (obj)
Az obj példány függvényeinek neveit adja vissza.
methods ("classname")
A classname nevű osztály függvényeit adja vissza.
Továbbá alkalmazhatóak rá az adatstruktúrákra vonatkozó függvények is, mint például az adattagok neveit visszaadó fieldnames (s).
Ha szeretnénk az osztály adattagjait lekérdezhetővé és beállíthatóvá tenni, ahhoz definiálnunk kell bizonyos függvényeket. Ezek közül a legegyszerűbb a display függvény. Ezt hívja meg az Octave, amikor az osztály egy példányát ki kell írni, mert például egy pontosvesszővel nem lezárt kifejezés eredménye. Ha ez a függvény nincs definiálva, akkor ebben az esetben semmi nem kerül a képernyőre.
A polinom osztály display függvénye lehetne például a következő:
A függvényt érdemes a fprintf ("%s =", inputname (1)); sorral kezdeni, hogy konzisztens legyen a beépített típusokkal, melyek szintén kiírják a változó nevét az objektum tartalma előtt.
Szintén konzisztencia miatt érdemes definiálni a get és
set függvényeket. A get függvény
egy vagy két argumentumot vár. Egy argumentum esetén egy, az
argumentumként kapott objektum adattagjait tartalmazó adatstruktúrát
ad vissza, két argumentum esetén a második argumentum által megnevezett
adattagját adja vissza az első argumentumként kapott objektumnak. Példa:
Hasonlóan, a set függvény a módosítandó objektumot várja, majd párosával egy beállítandó adattag nevét és az adattag új értékét. Példa:
Mivel Octave-ban nincs lehetőség referencia szerinti paraméterátadásra, így a set függvény a módosított objektumot adja vissza, és a következő módon kell meghívni:
Saját osztály egy példányát ugyanúgy el lehet menteni .m fájlba a save és load függvények segítségével, mint a beépített típusokat. Ha az osztálynak van saveobj(a) függvénye, akkor ez végrehajtódik mentés előtt, pl. eltávolíthatóak felesleges, származtatott vagy gyorsítótárazott értékeket tartalmazó adattagok. Ennek párja a loadobj(a), amely az fájl betöltése után hívódik meg, és itt elvégezhető pl. a mentéskor kitörölt adattagok visszahelyezése. Példák:
Minden Octave függvény túlterhelhető, hogy hívásakor egy osztályspecifikus eljárás fusson le. Mivel klasszikus OO értelemben vett tagfüggvények nincsenek, így helyette ezt a túlterhelési mechanizmust használhatjuk.
Például a plot függvényt túlterhelhetjük, hogy utána a felhasználó
által írt osztályok tartalmát is ki tudjuk rajzolni vele:
A függvény ezután így is hívható:
Külön érdekesség, hogy a típuskonverziót magvalósító függvények (pl.: double(a)) is túlterhelhetőek.
Lehetőség van az operátorok túlterhelésére is. Minden operátorhoz tartozik
egy függvénynév. Ha az osztálynak van ilyen nevű függvénye, akkor az
a függvény hívódik meg az operátor alkalmazásakor. Az operátorok és
a hozzájuk tartozó függvények:
Operátor | Függvény | Leírás |
---|---|---|
a + b | plus (a, b) | Összeadás |
a - b | minus (a, b) | Kivonás |
+ a | uplus (a) | Unáris plusz |
- a | uminus (a) | Unáris mínusz |
a .* b | times (a, b) | Elemenkénti szorzás |
a * b | mtimes (a, b) | Mátrixszorzás |
a ./ b | rdivide (a, b) | Elemenkénti jobbra osztás |
a / b | mrdivide (a, b) | Jobbra mátrixosztás |
a .\ b | ldivide (a, b) | Elemenkénti valra osztás |
a \ b | mldivide (a, b) | Balra mátrixosztás |
a .^ b | power (a, b) | Elemenkénti hatványozás |
a ^ b | mpower (a, b) | Mátrixhatványozás |
a < b | lt (a, b) | Kisebb |
a <= b | le (a, b) | Kisebb vagy egyenlő |
a > b | gt (a, b) | Nagyobb |
a >= b | ge (a, b) | Nagyobb vagy egyenlő |
a == b | eq (a, b) | Egyenlő |
a != b | ne (a, b) | Nem egyenlő |
a & b | and (a, b) | Logikai és |
a | b | or (a, b) | Logikai vagy |
! b | not (a) | Logikai nem |
a’ | ctranspose (a) | Adjungálás |
a.’ | transpose (a) | Transzponálás |
a : b | colon (a, b) | Két argumentumú intervallum operátor |
a : b : c | colon (a, b, c) | Három argumentumú intervallum operátor |
[a, b] | horzcat (a, b) | Vízszintes konkatenáció |
[a; b] | vertcat (a, b) | Függőleges összefűzés |
a(s_1, …, s_n) | subsref (a, s) | Indexelés |
a(s_1, …, s_n) = b | subsasgn (a, s, b) | Indexelt értékadás |
b (a) | subsindex (a) | 0 kezdetű indexszé alakítás |
display | display (a) | Parancssori megjelenítés |
A polinom osztály mtimes függvénye például nézhetne ki így:
Kérdés még, hogy ha egy függvény vagy operátor argumentumai különböző osztályba tartoznak, akkor melyikhez tartozó függvény vagy operátor hívódjon meg. Ennek meghatározására a superiorto és inferiorto beépített függvények szolgálnak. Ezeket csak az osztály konstruktorában hívhatóak meg, és azt határozhatjuk meg velük, hogy ha egy függvény vagy operátor argumentumai között az adott osztály és a class osztály egy-egy példánya is szerepel, akkor az adott osztály megfelelő függvénye (superiorto ("class")) vagy a másik osztály megfelelő függvénye (inferiorto ("class")) hívódjon meg.
Például ha a polynomial osztály konstruktorába beszúrjuk a
superiorto ("double"); sort, azzal jelezzük, hogy a
Hívás hatására a polynomial osztály mtimes függvénye hívódjon meg.
A példa szépséghibája, hogy ez az alapértelmezett viselkedés is, mivel a felhasználó által definiált típusok alapértelmezett módon magasabb preferenciával rendelkeznek, mint a beépített típusok.
Ha az argumentumok típusai között nincs preferencia-sorrend, akkor az előrébb szereplő változó típusához tartozó függvény hívódik meg.
Az Octave az osztályok öröklését is lehetővé teszi. Ehhez az osztály konstruktorában létre kell hozni az ősosztály egy példányát, majd ezt átadni harmadik paraméterként a class függvénynek. Többszörös öröklődés is támogatott, ehhez tetszőleges mennyiségű további hasonló paraméter adható meg a class függvénynek.
Ekkor az öröklő osztály extra adattagokként tárolja az ősosztályok egy-egy példányát. Az ősosztály függvényei azonban használhatóak, ha nincs felüldefiniálva, akkor az adattagon hívódik meg a hozzá tartozó függvény. Továbbá az isa függvény igazat ad vissza, ha azt kérdezzük le, hogy az öröklő osztály egy példánya az ősosztály egy példánya-e.