11. Classi e oggetti
Una classe è un tipo con nome, campi (stato) e metodi (comportamento). new ClassName(...) esegue il costruttore e restituisce un'istanza. Stesso file: Examples/OOP/classes_objects.malda.
11.1 Una classe funzionante
Il costruttore ha lo stesso nome della classe. Usa this.field quando un parametro nasconde un campo; altrove l'accesso ai membri può essere implicito. I metodi sono funzioni dichiarate dentro la classe.
class Person {
public var name;
public var age;
function Person(name, age) {
this.name = name;
this.age = age;
}
public function introduce() {
print("Hi, I'm " + name + " and I'm " + string(age) + " years old.");
}
public function getAge() {
return age;
}
public function setAge(newAge) {
age = newAge;
}
}
var person1 = new Person("Alice", 30);
var person2 = new Person("Bob", 25);
person1.introduce();
person2.introduce();
print("Alice's age: " + string(person1.getAge()));
person1.setAge(31);
print("Alice's new age: " + string(person1.getAge()));
new Person(...) se class Person non è dichiarata nello stesso programma (o importata). Uno snippet che mostra solo new Person non è un esempio completo.
11.2 Modificatori di accesso
- public: accessibile da qualsiasi punto (default per i metodi)
- private: accessibile solo all'interno della classe
- I campi sono private se non si specifica un modificatore
11.3 Ereditarietà
Una classe può estendere un solo padre con extends. Chiama super(...) dal costruttore figlio, e super.method() per riusare un metodo del padre. Stesso file: Examples/OOP/inheritance.malda.
class Animal {
public var name;
function Animal(name) {
this.name = name;
}
public function speak() {
print(name + " makes a sound");
}
}
class Dog extends Animal {
function Dog(name) {
super(name);
}
public function speak() {
print(name + " says: Woof!");
}
}
class Cat extends Animal {
function Cat(name) {
super(name);
}
public function speak() {
print(name + " says: Meow!");
}
}
var dog = new Dog("Rex");
var cat = new Cat("Fluffy");
dog.speak();
cat.speak();
Per eseguire anche l'implementazione del padre, chiama super.speak() dentro l'override prima o dopo il corpo del figlio.
11.4 Membri static
I membri static appartengono alla classe, non alle istanze:
class MathUtils {
static var PI = 3.14159;
static function add(a, b) {
return a + b;
}
}
var pi = MathUtils.PI;
var sum = MathUtils.add(5, 3);
11.5 Overload degli operatori
Le classi possono fare overload di operatori selezionati definendo metodi con nomi riservati. Per gli operatori binari, MALDA prova prima l'overload dell'operando sinistro (__add__, __sub__, ecc.). Se quell'overload non c'è, prova l'overload invertito dell'operando destro (__radd__, __rsub__, ecc.) passando l'operando sinistro come argomento. Per gli operatori unari, l'unico operando è il receiver.
| Operatore | Metodo dell'operando sinistro | Metodo di fallback dell'operando destro |
|---|---|---|
+ | __add__(other) | __radd__(other) |
- (binario) | __sub__(other) | __rsub__(other) |
* | __mul__(other) | __rmul__(other) |
/ | __div__(other) | __rdiv__(other) |
% | __mod__(other) | __rmod__(other) |
== | __eq__(other) | __req__(other) |
!= | __neq__(other) | __rneq__(other) |
< | __lt__(other) | __rlt__(other) |
<= | __le__(other) | __rle__(other) |
> | __gt__(other) | __rgt__(other) |
>= | __ge__(other) | __rge__(other) |
- (unario) | __neg__() | n/a |
Se non esiste un metodo di overload corrispondente né a sinistra né a destra, MALDA usa il comportamento built-in dell'operatore.
class Value {
public var data;
function Value(data) {
this.data = data;
}
public function __add__(other) {
return data + other.data;
}
}
var a = new Value(2);
var b = new Value(3);
print(a + b); // 5
class RightValue {
public var data;
function RightValue(data) {
this.data = data;
}
public function __radd__(other) {
return other + data;
}
}
var rhs = new RightValue(7);
print(5 + rhs); // 12
11.6 Costruttori primari
Una lista di parametri dopo il nome della classe è un costruttore primario. Ogni parametro diventa un campo public con lo stesso nome, e MALDA sintetizza un costruttore che assegna quei campi. Il corpo opzionale è un corpo di classe normale (metodi, campi extra, membri static, overload degli operatori). Non c'è una keyword aggiuntiva: class Name( è distinto da class Name { e da class Name extends.
Quelle forme si espandono in una classe classica: campi public, un costruttore con lo stesso nome della classe che assegna this.x = x (e così via), poi gli eventuali membri del corpo. I type hint opzionali sui parametri vengono memorizzati su quei campi: class Point(x: float, y: float).
- Solo dati:
class Point(x, y);oppureclass Point(x, y) { }. - Non dichiarare
function Point(...)nella stessa classe (costruttore duplicato). - Non dichiarare
var xnel corpo quandoxè già un parametro primario. extendsnon si può combinare con un costruttore primario. Usa una classe classica e chiamasuper(...).- Le istanze usano ancora l'uguaglianza per identità, a meno che tu non definisca
__eq__.
class Point(x, y);
var p = new Point(3, 4);
print(p.x + p.y);
class Point(x, y) {
function total() {
return this.x + this.y;
}
}
print(new Point(3, 4).total());
Vedi anche
- 4. Tipi di dati - Tipi oggetto
- 9. Funzioni - Metodi e funzioni
- 33. Esempi - Gli stessi programmi Person e Dog come campioni del catalogo