Klasy i obiekty¶
W wielu zastosowaniach szczególnie wygodnym podejściem jest programowanie z wykorzystaniem obiektów, które polega na definiowaniu klas, czyli złożonych typów danych wyposażonych definiujących dodatkowo operacje przewidziane do wykonania na tych danych
class Punkt:
def __init__(self,x,y):
self.x=x
self.y=y
def przesun(self,dx,dy):
self.x=self.x+dx
self.y=self.y+dy
class Prostokat:
def __init__(self,x,y,a,b):
self.wierzcholek=Punkt(x,y)
self.a=a #dlugosc prostokata
self.b=b #wysokosc prostokata
def pole(self):
return self.a*self.b
def przesun(self,dx,dy):
self.wierzcholek.przesun(dx,dy)
tworzeniu obiektów tego typu
obj=Prostokat(-3,-7,4,7)
oraz wykonywaniu na tych obiektach operacji zdefiniowanych w klasie, na przykład
a=obj.pole()
print a
lub
obj.przesun(3,-7)
Analogiczne definicje klas w języku Java miałby następującą postać
class Punkt
{
Punkt wierzcholek;
int a;
int b;
Prostokat(int x,int y,int a,int b)
{
this.wierzcholek=new Punkt(x,y);
this.a=a;
this.b=b;
}
void przesun(int dx, int dy)
{
this.x += dx;
this.y += dy;
}
class Prostokat
{
int x;
int y;
Prostokat(int x,int y)
{
this.x=x;
this.y=y;
}
int pole()
{
return this.a*this.b;
}
void przesun(int dx, int dy)
{
this.wierzcholek.przesun(dx,dy);
}
}
Odpowiednie operacje na obiektach w języku Java będą miały następującą postać
Prostokat obj; //deklaracja
obj = new Prostokat(0,0,3,7); //utworzenie instancji obiektu za pomocą operatora
//new i konstruktora
obj.przesun(-6,0); //wywołanie metody typu void na rzecz obiektu
int x=obj.pole(); //wywołanie metody zwracającej typ int, na rzecz obiektu
Każda klasa w języku Java dziedziczy po klasie java.lang.Object, nawet jeżeli nie jest to jawnie zadeklarowane w definicji klasy.
W języku Objective-C analogiczne definicje klas są nieco bardziej złożone, stąd dla przejrzystości ograniczymy się do klasy Punkt.
@interface Punkt : NSObject
{
int x;
int y;
}
-(void)setXwith:(int)x andYwith:(int)y;
-(void)przesunOdx:(int)dx iOdy:(int)y;
@end
@implementation Punkt
-(void)setXwith:(int)x andYwith:(int)y
{
self->x=x;
self->y=y;
}
-(void)przesunOdx:(int)dx iOdy:(int)dy
{
self->x+=dx;
self->y+=dy;
}
@end
Definicja składa się z dwóch części - interfejsu zawierającego deklaracje zmiennych i nagłówki metod (funkcji składowych) oraz z implementacji zawierającej definicje tych metod. Według konwencji każdą z tych części zapisujemy w oddzilnym pliku - interfejs w pliku nagłówkowym (.h), natomiast implementację w pliku implementacyjnym (.m).
Odpowiednie operacje na obiektach tej klasy mają następującą postać
Punkt* obj; //deklaracja objektu klasy Punkt (obj jest wskaźnikiem, podobnie jak w C++)
obj=[[Punkt alloc] init]; //utworzenie instancji obiektu (alloc) i inicjalizacja (init)
//oraz przypisanie go do zmiennej obj
[obj setXwith:7 andYwith:6]; //wywołanie metody na rzecz obiektu obj i przekazanie
//dwóch parametrów
[obj przesunOdx:-1 iOdy:7]; //wywołanie metody przesun na rzecz obiektu i przekazanie
//do niej dwóch parametrów
Inaczej niż w języku Java, wywołanie metody na rzecz obiektu (wysyłanie komunikatu do obiektu) odbywa się przy użyciu notacji wykorzystującej nawiasy kwadratowe.
[obiekt metoda]
Zwróć także uwagę na różnice w składni dotyczącej definicji metod (funkcji składowych) w odróżnieniu od innych funkcji w języku Objective-C (a także od metod w języku Java). Metody w Objective-C definiuje się wykorzystując podzieloną nazwę funkcji oraz parametry przekazywane po dwukropku.
[obiekt pierwszaCzescNazwyMetody: parametr1 drugaCzescNazwyMetody: parametr2]
Kolejną ważną rzeczą jest brak konstruktorów. Obiekt jest tworzony poprzez wywołanie metody alloc, która przydziela pamięć dla obiektu, a następnie przez wywołanie metody init , która inicjuje pola obiektu. Przez konwencję, przyjmuje się że nazwy metod inicjalizujących pola obiektu powinny rozpoczynać się od członu init.
Podobnie jak w przypadku klas w języku Java, każda klasa dziedziczy po wspólnej nadklasie, w tym przypadku po klasie NSObject.
Język Objective-C nie wspiera przeciążenia operatorów. Inaczej mówiąc nie mogą istnieć dwie funkcje o tej samej nazwie, nawet jeżeli różnią się listą parametrów albo typem wartości zwracanej.
void funkcja1(int i);
void funkcja1(double x);
To samo dotyczy metod, czyli funkcji składowych klas.
-(int) metoda1:(int) x;
-(int) metoda1:(float) x;
-(int) metoda1:(int) x :(int) y;
-(int) meto:(int) x da1:(float) y;
Analogiczny zapis w języku Pyton lub Java byłby w pełni uprawniony.