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.

Następna część - Dziedziczenie i polimorfizm