Co to są klasy i obiekty – na przykładzie języka Ruby

Opublikował siefca śr 25 mar 2009 07:56:24 GMT

Jakiś czas temu, przy okazji opisywania podstaw Rails, starałem się wyjaśnić co to są klasy i obiekty. Jednak takie miksowanie poziomów ogólności w jednym wpisie może sprawiać, że całość wyda się mało przystępna dla początkujących i nudna dla obeznanych z tematem. Napiszę więc krótko o programowaniu obiektowym dla wszystkich tych, którzy znają już jakieś inne imperatywne, ale nie obiektowe języki programowania i chcą poznać czym są obiekty i klasy.

Zmienne i ich typy

Z pewnością wiesz, że 31337 to liczba całkowita, a "siała baba mak" to łańcuch znaków. Programując, na przykład w języku C, musisz deklarować jakiego typu dane będą przechowywane pod adresem w pamięci przypisanym do tworzonej zmiennej. W tym celu użyjesz na przykład konstrukcji int a = 31337;, gdzie int jest nazwą typu, a to nazwa zmiennej, a 31337 jest jej początkową wartością. Wyspecyfikowanie typu jest potrzebne kompilatorowi, aby tłumacząc kod na język maszynowy wiedział ile przestrzeni powinien zarezerwować na tę „szufladkę” do przechowywania informacji.

W językach średniego i niskiego poziomu często musimy przejmować się pamięcią zajmowaną przez zmienne. Dzieje się tak dlatego, że im niższego poziomu jest język, tym bliżej mu do maszyny, a dalej do człowieka. Oznacza to, że programista musi uwzględniać np. kolejności bajtów w długich liczbach czy dbać o to, aby po użyciu dużych tablic zajmowana przez nie pamięć została zwolniona. W językach wysokiego poziomu zajmuje się tym kompilator lub interpreter.

Zmiennych używa się w instrukcjach i wyrażeniach realizowanych przez program. Gdy programista pisze kod, to stara się przenieść jakiś problem z rzeczywistego świata do komputera, aby korzystając z jego mocy obliczeniowej szybciej go rozwiązać. Jednak mając tylko kilka typów danych, które zostały pomyślane bardziej z myślą o maszynie niż człowieku, trzeba się czasem porządnie nagimnastykować. Na przykład jeśli zamierzamy stworzyć program przechowujący dane osobowe, takie jak wiek, imię i nazwisko i płeć, to programując na średnio-niskim poziomie musimy utworzyć osobną zmienną przechowującą wiek (liczba całkowita o dł. jednego bajtu), osobną na łańcuch tekstowy z imieniem i nazwiskiem (tablica bajtów zakończona znakiem o kodzie 0), osobną zmienną mówiącą czy osoba jest płci męskiej czy żeńskiej (zmienna typu boolean o długości jednego bitu, choć w praktyce może być przezroczyście rzutowana na jeden bajt).

klasa

Akurat w języku C mamy pewne ułatwienie w postaci tzw. struktur – typu danych pozwalającego związać inne typy w spójną całość widoczną pod jakąś nazwą. Dzięki tej atrapie program staje się bardziej czytelny, ale wciąż trzeba pamiętać o osobnym przetwarzaniu każdej informacji. W końcu zechcemy pewnie zdefiniować tablicę osób, czyli tak naprawdę tablicę wskaźników do miejsc w pamięci, w których znajdują się struktury zawierające wspomniane pola. Jeszcze tylko zarządzanie tą tablicą, przydzielanie i zwalnianie pamięci, podstawowe operacje wyszukiwania, dodawania i kasowania… brzmi nieco koszmarnie.

Klasa i obiekt

Dlatego właśnie ktoś pomyślał kiedyś, że znacznie przyjemniej byłoby, gdyby dało się tworzyć własne typy danych i to nie w celu zadowolenia komputera, ale w celu lepszego operowania na abstrakcyjnych informacjach przez człowieka. Języki pozwalające tworzyć takie typy danych nazywa się właśnie językami obiektowymi, ponieważ zamiast zmiennych występują tam obiekty, a zamiast typów klasy. Na obiekty mówi się też egzemplarze klasy lub instancje klasy. Oczywiście zmienne istnieją w językach obiektowych, ale często przechowują odwołania do obiektów a nie bezpośrednio jakieś pojedyncze wartości.

Wyobraź sobie, że zamiast typu oznaczającego liczbę całkowitą i osobnego typu przechowującego pojedyncze znaki masz możliwość skorzystania z typu Osoba, który pozwala zmieścić wiek, imię i nazwisko, a także płeć. Oczywiście nie uświadczysz takiego gotowego typu danych, jednak możesz go samodzielnie stworzyć.

Oto przykład definiowania klasy:

  class Osoba; end

Żeby zapamiętać do czego służy klasa wystarczy skojarzyć sobie, że dokonujemy klasyfikacji danych jakiegoś typu, w taki sposób, że wyróżniamy wspólne dla nich operacje i struktury w pamięci zdolne je pomieścić. Z kolei obiekt możesz sobie wyobrazić jako coś bardziej namacalnego, co jest tworzone w oparciu o wytyczne zawarte w klasie.

Składowe

Klasa posiada składowe, to znaczy, że podczas jej definiowania określasz z jakich elementów będzie się składać. Część z nich służy do przechowywania danych, a część do operowania na nich.

W większości popularnych, obiektowych języków programowania istnieje operator pozwalający na dostęp do jakiejś składowej klasy – nazywa się on operatorem wyboru składowej lub operatorem kropki. Po nazwie obiektu stawia się kropkę, a po niej podaje nazwę składowej, czyli składnika klasy. Jeśli tym składnikiem jest na przykład definiowana w klasie funkcja, to dla danego obiektu tej klasy zostanie ona wywołana, a jej wynik zwrócony.

W języku Ruby, podobnie jak w innych językach obiektowych, składowymi są pola i metody.

Pola

Pola, nazywane czasem zmiennymi instancyjnymi lub zmiennymi egzemplarza (bo należą do egzemplarza klasy czyli obiektu) są składowymi służącymi do przechowywania danych obiektu. Jeśli przykładowa klasa Osoba ma określać ile ktoś ma lat i jakiej jest płci, to możesz stworzyć odpowiednie pola o wskazujących na zawartość nazwach:

klasa-i-obiekt

Klasa może mieć tyle pól ile zapragniesz. W języku Ruby nie musisz deklarować, jakich typów będą pola, czy raczej, jakich klas obiektami one będą. Nie musisz nawet ich wprost deklarować opisując klasę. Pola osadzone są w obiektach. Co to oznacza? Materializowane są dopiero w momencie utworzenia jakiegoś opisywanego za pomocą klasy obiektu. Nie można też uzyskać bezpośrednio dostępu do jakiegoś pola obiektu posługując się operatorem wyboru składowej. Wychodzi więc na to, że zmienne instancji w języku Ruby są prywatną sprawą obiektów, w których istnieją.

Jeśli w metodzie operującej na obiekcie spróbujesz odczytać jakieś pole, którego wartość nie została ustawiona, to zwrócony zostanie obiekt nil.

Zmienne instancyjne obiektu w Rubym charakteryzują się tym, że przed ich nazwami występuje znak @, np. @wiek.

Metody

W językach obiektowych rozwiązano problem polegający na rozdzieleniu operacji od danych na których się operuje i wprowadzono pojęcie metody. Metoda to nic innego jak funkcja składowa klasy, która służy do dokonywania operacji na obiektach tej klasy.

Ponieważ w języku Ruby zmienne instancji widoczne są tylko dla metod klasy, więc to właśnie metody są jedynym sposobem na to, aby można było odpytać obiekt o jego właściwości, np. obiekt klasy Osoba o wiek czy płeć. Podobnie tworzy się też metody, które będą ustawiały wartości pewnych pól. Oto przykład klasy zawierającej takie metody:

  class Osoba

    # metoda odczytująca pole wiek
    def wiek(x)
      return @wiek
    end

    # metoda ustawiająca pole wiek
    def wiek=(x)
      @wiek = x
    end

  end

Taka klasa ma tylko jedną zmienną instancyjną @wiek, która powoływana jest to życia po wywołaniu metody wiek=. Ta dziwna, zakończona operatorem przypisania nazwa funkcji ma specjalne znaczenie syntaktyczne. Zostanie ona wywołana za każdym razem, gdy w programie pojawi się tego typu wywołanie:

  obiekt.wiek = 1234

Jest ono równoważne zapisowi:

  obiekt.wiek=(1234)

Jeśli chcesz możesz stworzyć metodę ustaw_wiek, jednak wtedy będzie to mniej przejrzyste w zapisie. Metody zlokalizowane są w klasie a nie w obiekcie, chociaż fakt ten jest przed Tobą ukrywany. Byłoby to marnotrawieniem pamięci, gdyby każdy tworzony obiekt targał ze sobą kopie wszystkich funkcji składowych, które powinien mieć. Rozwiązano to więc w ten sposób, że w przypadku metod, inaczej niż w przypadku pól, w instancji klasy (czyli obiekcie) znajdują się tylko odwołania do miejsc w klasie, pod którymi funkcje składowe już czekają, żeby ich użyć.

klasa

Można powiedzieć, że metody obiektu są pewnego rodzaju interfejsem pozwalającym mu inter-reagować z innymi obiektami, czy w inny sposób uczestniczyć w procesie uruchamiania się programu.

Akcesory

Poprzednie przykłady dotyczące pól były pisane w przebiegły sposób, to znaczy miały doprowadzić nas do tego punktu. Wyobraź sobie klasę, która ma 5 czy więcej pól, przy czym pierwsze trzy powinno dać się bez przeszkód zapisywać i odczytywać, przedostanie tylko ustawiać, a ostatnie jedynie odczytywać. W takim przypadku możesz napisać następujący kod:

  class Osoba

    # metody odczytujące pola
    def pole1(x); @pole1 end
    def pole2(x); @pole2 end
    def pole3(x); @pole3 end
    def pole5(x); @pole5 end

    # metody zapisujące pola
    def pole1=(x); @pole1 = x end
    def pole2=(x); @pole2 = x end
    def pole3=(x); @pole3 = x end
    def pole4=(x); @pole4 = x end

  end

W stosunku do poprzedniego przykładu usunąłem słowo kluczowe return, ponieważ można je stosować, ale nie trzeba – metoda i tak zwraca rezultat ostatnio wykonywanego wyrażenia. Poza tym użyłem średnika jako separatora, żeby zmieścić definicję każdej z metod w jednej linii.

Jednak twórcy Ruby’ego pomyśleli o takich częstych operacjach i w związku z tym istnieją słowa kluczowe pozwalające szybciej zdefiniować tzw. akcesory, w tym settery (metody do ustawiania pól) i gettery (metody do odczytywania ich zawartości). Oto jak można łatwiej zakodować poprzednio wyspecyfikowane zachowanie:

  class Osoba

    # metody odczytujące i zapisujące pola
    attr_accessor :pole1, :pole2, :pole3

    # metody odczytujące pola
    attr_reader :pole5

    # metody zapisujące pola
    attr_writer :pole4

  end

Skrót attr bierze się z tego, że na pola mówi się też atrybuty klasy. Dwukropek przed nazwami pól podawanymi jako argumenty zmienia następujący po nim łańcuch tekstowy w tzw. symbol. Symbole w Rubym to takie wydajne łańcuchy znaków. Są wydajne, ponieważ są internalizowane. Internalizacja w skrócie polega na przechowywaniu w jednym miejscu w pamięci łańcuchów, które są takie same. Słowo kluczowe, np. attr_reader jest pseudofunkcją, która przyjmuje tablicę symboli i dla każdego z nich definiuje metodę służącą do odczytu zmiennej egzemplarza (czyli pola obiektu) o danej nazwie.

Życie obiektu

Nie napisałem jeszcze, jak tworzy się nowy obiekt jakiejś klasy. Służy do tego metoda klasowa new:

  obiekt = Osoba.new

Co się stało? Po pierwsze po lewej stronie wyrażenia przypisania stworzona została zmienna o nazwie obiekt. Będzie ona zawierała referencję, czyli odniesienie do miejsca w pamięci, pod którym umieszczony zostanie nowo powstały obiekt klasy Osoba.

Z kolei po prawej stronie wyrażenia mamy stałą o nazwie Osoba, która wcześniej została skojarzona z miejscem w pamięci, pod którym rezyduje zaprezentowana wcześniej definicja klasy. Tak, w języku Ruby pierwotne wskazania na klasy są przechowywane w stałych, a stałe w tym języku można poznać po tym, że ich nazwy zapisujemy zawsze rozpoczynając je wielką literą. Wynika z tego, że nazwy klas też podlegają tej regule.

Po nazwie stałej jest wywołanie metody new. Powinno to Cię zastanowić, bo po pierwsze nie była tworzona żadna taka metoda, a po drugie przecież nie mamy do czynienia z obiektem, ale z klasą. Czy to nie jest czasem odwołanie do metody, która przecież zawsze „siedzi w klasie”? Otóż nie. Wyjaśnię to poniżej, natomiast w tym miejscu ważne jest, żeby wiedzieć, iż metoda ta tworzy nowy obiekt klasy, dla której ją wywołano i zwraca referencję wskazującą na ten obiekt. Jak łatwo się domyślić wynik powędruje do zmiennej obiekt, która będzie reprezentowała go w programie.

Konstruktor

Obiekty posiadają swoje konstruktory, czyli metody, które wykonywane są za każdym razem, gdy instancje zaczynają istnieć. W języku Ruby konstruktorem jest metoda o nazwie initialize. Zwykle ustawia się w niej domyślne wartości pól i wykonuje inne potrzebne rzeczy. Dla każdego nowo stworzonego obiektu będzie wywołana metoda initialize. Możemy przekazać jej argumenty, jeśli tego potrzebujemy, ale trochę pośrednio, bo wyręczy nas w tym metoda klasowa new, która odda podane jej argumenty właśnie konstruktorowi.

  class Osoba

    def initialize(imie=nil)
      @wiek = 12345
      @plec = false
      @imie = imie unless imie.nil?
    end

  end

  mariola = Osoba.new 'Mariola'
  p mariola.wiek  # => 12345
  p mariola.imite # => Mariola

Gdzie naprawdę są pola a gdzie metody?

W języku Ruby, podobnie jak w innych językach obiektowych, składowymi są pola i metody. Pola przypisane są do obiektu tworzonego na podstawie klasy, a metody przypisane są do klasy, choć można używać ich w obiektach.

Nazywamy je składowymi, bo podczas tworzenia zarysu programu nie musimy pamiętać o tym, gdzie naprawdę przechowywany jest dany element. Po prostu łatwiej jest założyć, że „klasa ma pola”, choć tak naprawdę dopiero metody instancyjne mogą zawierać odwołania do pól obiektu, a te powstaną dopiero, gdy stworzony zostanie konkretny obiekt.

Zapamiętaj więc ogólną zasadę:

Obiekty służą do przechowywania zmiennych instancyjnych, natomiast w klasach można przechowywać nie tylko zmienne, ale również metody.

Ta druga część zdania jest prawdziwa dlatego, że w Rubym klasa też jest obiektem, czyli tworząc klasę tak naprawdę stwarzasz pewien specyficzny obiekt. Oczywiście nie działa to w drugą stronę i nie każdy obiekt jest klasą. Wspomnę jeszcze o tym.

Metody klasowe

Powiem trochę więcej o tej dziwnej i ciekawej zarazem konstrukcji:

  obiekt = Osoba.new

Zauważ, że wywołujemy tutaj metodę klasy, a nie metodę obiektu. Takie metody nazywamy metodami klasowymi a w niektórych językach statycznymi metodami. W obiektach klasy Osoba trudno więc szukać metody new.

Metoda klasowa przydaje się wtedy, gdy mamy do czynienia z operacjami, które nie muszą mieć dostępu do pól konkretnych obiektów, jednak może być użyta do zrobienia czegoś w odniesieniu do nowego typu danych. Na przykład w klasie Osoba mogłaby zostać zdefiniowana metoda klasowa, która dla każdej osoby, nie ważne jakiej, jest w stanie stwierdzić jakiej w przybliżeniu jest płci na podstawie imienia:

  class Osoba

    # definiowanie metody klasowej
    # przedrostek self. sygnalizuje, że tworzymy metodę dla klasy
    def self.plec?(imie)
      imie.downcase.slice(-1) == 'a' ? 'kobieta' : 'mężczyzna'
    end

  end

  Osoba.plec? "Mariola"  # => kobieta

Z wnętrza metody instancyjnej możemy dobrać się do metody klasowej w taki sposób:

  class Osoba

    def plec?(imie)
      self.class.plec(imie)  # wywołanie metody klasowej
    end

  end

  obiekt = Osoba.new
  obiekt.plec? "Mariola"  # => kobieta

Możemy też skorzystać z niej w bardziej praktyczny sposób, np. aby ustawiać płeć na podstawie imienia, jeśli jeszcze płci nie określono. Dla czytelności stworzę całą klasę:

  class Osoba
    attr_accessor :plec, :wiek
    attr_reader :imie

    # metoda klasowa wykrywająca płeć
    # zwraca false w przypadku kobiety
    # zwraca true w przypadku mężczyzny
    def self.plec?(imie)
      imie.downcase.slice(-1) != 'a'
    end

    # metoda instancyjna podająca płeć
    # na podstawie zmiennej instancyjnej @plec
    def plec?
      @plec ? 'chlop' : 'baba'
    end

    # metoda ustawiająca imię, czyli setter
    # przy okazji wywołuje metodę klasową plec
    # i na tej podstawie ustawia pole @plec
    # jeśli nie zostało ono ustawione (jest nil)
    def imie=(imie)
      @imie = imie
      @plec = self.class.plec?(imie) if @plec.nil?
    end

  end

  # tworzenie obiektów
  mariola = Osoba.new
  stefan = Osoba.new

  # nadawanie imion
  mariola.imie = "Mariola"
  stefan.imie = "Stefan"

  # odpytywanie o płcie
  p mariola.plec?  # => baba
  p stefan.plec?   # => chlop

Metody instancyjne, czyli te które można wywoływać dla obiektów, pamiętane są wewnątrz klasy, gdzie więc zapamiętywane są metody klasowe? Specjalnie dla nich tworzona jest dodatkowa, ukryta przed programistą, dodatkowa klasa zwana metaklasą lub klasą własną opisującą inną klasę. Jest to wirtualny towarzysz każdej klasy, generowany wtedy, gdy pojawi się taka potrzeba. O metaklasach postaram się jeszcze napisać.

Wiesz już, czym jest metoda new, ale nie wiesz kiedy została zdefiniowana. Zajmiemy się tym później, przy okazji omawiania dziedziczenia, ważnej cechy języków obiektowych.

Zmienne klasowe

Skoro istnieją klasowe metody, to konsekwentnie korzystać możemy również z klasowych zmiennych, czyli z atrybutów niezależnych od obiektów, ale związanych z daną klasą. Dzięki nim możesz pamiętać dane, które są wspólne dla wszystkich obiektów. Na przykład możesz używać zmiennej klasowej, żeby pamiętać ilość wszystkich ludzi:

  class Osoba
    # wszyscy ludzie
    @@suma = 0

    # akcesory
    attr_accessor :imie, :plec, :wiek

    # konstruktor
    def initialize
      @@suma += 1
    end

  end

  # tworzenie pięciu obiektów
  5.times { Osoba.new }

  # wyświetlanie zawartości zmiennej klasowej @@suma
  p Osoba.class_variable_get :@@suma

W metodzie initialize wywoływanej za każdym razem, gdy tworzony jest nowy obiekt znajduje się wyrażenie, które zwiększa wartość zmiennej klasowej @@suma o jeden. W związku z tym zawierała ona będzie liczbę odpowiadającą liczbie stworzonych obiektów klasy Osoba.

Zmienne klasowe (lub innymi słowy pola klasowe) w języku Ruby przechowywane są w klasie, a jak widać na powyższym listingu, aby z nich skorzystać używa się dwóch znakow @ umieszczonych przed nazwą. Gdy interpreter języka widzi zapis @@zmienna bezpośrednio w kontekście klasy, to odwołuje się do zmiennej o tej nazwie składowanej w klasie. Jeśli natomiast konstrukcja taka zostanie wywołana w kontekście instancji (np. w uruchomionej korzystając z obiektu metodzie instancyjnej), to poszukiwana jest klasa tego obiektu i tam odnajdywana jest zmienna. Dlatego zmienne klasowe można zapisywać tak samo w metodach instancyjnych, metodach klasowych i samej klasie.

Niektórzy radzą, żeby unikać, tam gdzie się da, korzystania ze zmiennych klasowych.

Zmienne instancyjne klasy

Zmienne instancyjne klasy kojarzą się z jakimś dziwnym wynalazkiem podobnym do świnki morskiej (ni to świnka, ni to morska). Jednak przypominając sobie slogan „w Rubym wszystko jest obiektem” ma to sens. Skoro klasa jest również obiektem, a więc tak samo jak każdy obiekt może mieć swoje własne zmienne instancyjne – taka nazwa może być wieloznaczna, bo mocno zależy od kontekstu, dlatego używa się dopełniacza „klasy”. Jeżeli traktujemy klasę tak jak obiekt, to będą to po prostu zmienne instancyjne tego obiektu, jeśli natomiast mamy na myśli nieco szerszą perspektywę, w tym obiekty tej klasy, to warto dodać, że chodzi o zmienne instancyjne tej klasy, a nie o zmienne instancyjne obiektów tej klasy (nazywane w skrócie zmiennymi instancyjnymi).

Zmienne instancyjne klasy różnią się od zmiennych klasowych tym, że nie można mieć do nich bezpośredniego dostępu w kontekście obiektu (np. w metodzie instancyjnej wywołanej dla obiektu). Widać je tylko w samej klasie i w metodach klasowych.

Oto przykład wykorzystania zmiennej instancyjnej obiektu, którym jest jakaś klasa:

  class Osoba
    # wszyscy ludzie
    @suma = 0

    # akcesory dla zmiennej instancyjnej klasy
    def self.suma; @suma end
    def self.suma=(x); @suma = x end

    # akcesory dla zmiennych instancyjnych obiektów
    attr_accessor :imie, :plec, :wiek

    # konstruktor
    def initialize
      self.class.suma += 1
    end

  end

  # tworzenie pięciu obiektów
  5.times { Osoba.new }

  # wyświetlanie zawartości zmiennej instancyjnej klasy @suma
  p Osoba.suma

I przykład, który warto pamiętać ucząc się języka Ruby:

  class Osoba
    @suma = 0  # zmienna instancyjna klasy

    # metoda klasowa odczytująca zmienną instancyjną klasy
    def self.suma
      @suma
    end

    # metoda odczytująca zmienną instancyjną obiektu
    def suma
      @suma  # to zupełnie inna zmienna niż poprzednia!!!
    end
  end

Podsumowanie

Podsumowując, klasa to nowy typ danych, pewien rodzaj wzorca, który jest matrycą dla powoływanych do życia obiektów stworzonych w oparciu o niego. Może ona zawierać składowe, czyli pola i metody, ale tak naprawdę sama klasa nie służy do przechowywania danych – informacje którymi chcemy zarządzać z użyciem klasy zaczynają „żyć w pamięci” dopiero, gdy na podstawie klasy stworzymy obiekt. Klasa jest trochę jak coś subtelnego i duchowego, niczym idea na zorganizowanie czegoś. Z kolei obiekt jest materializacją klasy, jej wyrazem w pamięci zajmującym miejsce i trwającym przez pewien czas. Można też użyć prostszej analogii, która jest łatwa do zapamiętania: klasa to foremka, a obiekty (instancje tej klasy) to ciastka upieczone w tej foremce.

Na koniec małe zestawienie elementów programowania obiektowego i ich cech:

ElementInne nazwyZastosowaniePrzykład
klasawzorzectworzenie typu danychclass Osoba; end
metaklasaklasa własna opisująca klasę,
klasa typu singleton opisująca klasę
uzupełnianie właściwości typu danychclass Osoba << self
end
obiektegzemplarz, instancjaprzechowywanie danychosoba = Osoba.new
klasa własna obiektuklasa własna opisująca obiekt,
klasa typu singleton opisująca obiekt
uzupełnianie właściwości obiektuclass Osoba; end
osoba = Osoba.new
osoba << self
end
zmienna instancyjnapole,
zmienna egzemplarza
przechowywanie danych obiektuclass Osoba
  def ustaw_wiek
    @wiek = 18
  end
end
zmienna klasowapole klasy,
zmienna statyczna klasy
przechowywanie danych klasyclass Osoba
  @@liczba = 5
end
zmienna instancyjna klasyzmienna metaklasy,
pole metaklasy
przechowywanie danych metaklasyclass Osoba
  @suma = 5
  def self.daj_sume
    return @suma
  end
end
Osoba.daj_sume
metoda instancyjnametoda,
funkcja składowa
operowania na polach obiektuclass Osoba
  def dodaj(x)
    @x=x
  end
end
osoba = Osoba.new
osoba.dodaj 5
metoda klasowafunkcja statyczna,
statyczna funkcja składowa,
metoda statyczna
operowania na danych niezwiązanych z obiektemclass Osoba
  def self.ustaw(x)
    @@x=x
  end
end
Osoba.ustaw 5
metoda singletonowametoda własna,
metoda własna egzemplarza
definiowania operacji dla konkretnego obiektucap = Osoba.new
def cap.smrod(x)
  @smrod=x
end
cap.smrod 1000
ElementOpisywany przez…Dostępny w…Rzeczywiście składowany w…
klasaklasę Class i ew. metaklasęprogramiepamięci przeznaczonej na klasy i obiekty
metaklasaklasę Classklasie i programiepamięci przeznaczonej na klasy i obiekty
obiektklasę i ew. klasę własnąprogramiepamięci przeznaczonej na klasy i obiekty
klasa własna obiektuklasęobiekcie i programiepamięci przeznaczonej na klasy i obiekty
zmienna instancyjnametodach instancyjnychobiekcie
zmienna klasowaklasie i metodach instancyjnych oraz klasowychklasie
zmienna instancyjna klasyklasie i metodach klasowychklasie
metoda instancyjnaobiekcieklasie
metoda klasowaklasiemetaklasie
metoda singletonowaobiekcieklasie własnej obiektu

I schemat obrazujący miejsce ich przechowywania dla dociekliwych:

klasy-obiekty-relacje

Podziel się

Trackbacki

Użyj następującego trackbacka na swojej stronie:

http://randomseed.pl/trackbacks?article_id=klasy-i-obiekty&day=26&month=03&year=2009

Komentarze

  1. bezimx@tenbit.pl powiedział 11 months later:

    Witam !

    W definicji klasy :

    class Osoba def plec?(imie) self.class.plec(imie) end

    end

    powinno byc :

    self.class.plec?(imie)

    Sprawdzono w Ruby ver: 1.8.7 (2009-06-12 patchlevel 174) [i486-linux]

    Pozdrawiam !
     Piotr
    Ten komentarz oczekuje na akceptację. Nie ukaże się do czasu zaakceptowania przez autora..
  2. bezimx (at) tenbit (dot) pl powiedział 11 months later:

    Witam !

    W definicji klasy :

    class Osoba def plec?(imie) self.class.plec(imie) end

    end

    powinno byc :

    self.class.plec?(imie)

    Sprawdzono w Ruby ver: 1.8.7 (2009-06-12 patchlevel 174) [i486-linux]

    Pozdrawiam !
     Piotr
    Ten komentarz oczekuje na akceptację. Nie ukaże się do czasu zaakceptowania przez autora..
  3. BezYmienny powiedział 11 months later:

    Witam !

    W definicji klasy :

    class Osoba def plec?(imie) self.class.plec(imie) end

    end

    powinno byc :

    self.class.plec?(imie)

    Sprawdzono w Ruby ver: 1.8.7 (2009-06-12 patchlevel 174) [i486-linux]

    Pozdrawiam !
     Piotr
    Ten komentarz oczekuje na akceptację. Nie ukaże się do czasu zaakceptowania przez autora..
  4. BezYmienny powiedział 11 months later:

    Witam !

    W definicji klasy :

    class Osoba def plec?(imie) self.class.plec(imie) end

    end

    powinno byc :

    self.class.plec?(imie)

    Sprawdzono w Ruby ver: 1.8.7 (2009-06-12 patchlevel 174) [i486-linux]

    Pozdrawiam !
     Piotr
    Ten komentarz oczekuje na akceptację. Nie ukaże się do czasu zaakceptowania przez autora..
  5. BezYmienny powiedział 11 months later:

    Witam !

    W definicji klasy :

    class Osoba def plec?(imie) self.class.plec(imie) end

    end

    powinno byc :

    self.class.plec?(imie)

    Sprawdzono w Ruby ver: 1.8.7 (2009-06-12 patchlevel 174) [i486-linux]

    Pozdrawiam !
     Piotr
    Ten komentarz oczekuje na akceptację. Nie ukaże się do czasu zaakceptowania przez autora..
  6. BezYmienny powiedział 11 months later:

    Witam !

    W definicji klasy :

    class Osoba def plec?(imie) self.class.plec(imie) end

    end

    powinno byc :

    self.class.plec?(imie)

    Sprawdzono w Ruby ver: 1.8.7 (2009-06-12 patchlevel 174) [i486-linux]

    Pozdrawiam !
     Piotr
    Ten komentarz oczekuje na akceptację. Nie ukaże się do czasu zaakceptowania przez autora..
  7. BezYmienny powiedział 11 months later:

    Witam !

    W definicji klasy :

    class Osoba def plec?(imie) self.class.plec(imie) end

    end

    powinno byc :

    self.class.plec?(imie)

    Sprawdzono w Ruby ver: 1.8.7 (2009-06-12 patchlevel 174) [i486-linux]

    Pozdrawiam !
     Piotr
    Ten komentarz oczekuje na akceptację. Nie ukaże się do czasu zaakceptowania przez autora..
  8. programy powiedział about 1 year later:

    świetnie wytłumaczone- za co dziękuję

    Ten komentarz oczekuje na akceptację. Nie ukaże się do czasu zaakceptowania przez autora..
  9. programy powiedział about 1 year later:

    świetnie wytłumaczone- za co dziękuję

    Ten komentarz oczekuje na akceptację. Nie ukaże się do czasu zaakceptowania przez autora..

(leave url/email »)

   Pomoc języka formatowania Obejrzyj komentarz