Jacek Matulewski
Projektowanie klas w C++, Javie, Object Pascalu i C#
wersja z dnia: 22 VIII 2004

W serii kilkunastu kroków przedstawione jest projektowanie klasy Ulamek od deklaracji jej pól i metod, aż do omówienia podstaw dziedziczenia. Klasa służąca jako przykład to implementacja ułamka zwykłego.


Spis treści:

  1. Deklaracja klasy, pola
  2. Deklaracja klasy, metody
  3. Obsługa błędów w konstruktorze klasy wykorzystująca wyjątki
  4. Konstruktor
  5. Własne klasy wyjatków
  6. Konstruktor copy
  7. Obiekty stałe
  8. Działania określone dla klasy, operatory
  9. Operatory/funkcje konwersji
  10. Metoda "uproszczenie ułamka"
  11. Rozdzielenie deklaracji i definicji klasy, pliki nagłówkowy i zródłowy
  12. Szablon klasy
  13. Dziedziczenie publiczne
Źródła: Borland C++ Builder 6/JBuilder 6 Personal/Borland Delphi 6 Personal/Borland C# Builder 1

Język programowania:

Uwaga! Mechanizm wyboru języka wymaga zapisania cookie.


Uwaga! (C++)
Kod klasy ulamek pisany jest w czystym C++ i jest w pełni przenaszalny (można zastosować inne kompilatory np. gcc, także pod Linuxem). Przykłady ilustrujące wykorzystanie opisywanej tu klasy korzystają z funkcji WinAPI ShowMessage() i są napisane w C++ Builder 6. Funkcję tą można z powodzeniem zastąpić przekazywaniem tekstu do stanardowego strumienia wyjścia. Tzn. wszędzie tam, gdzie znajduje się jej wywołanie, np.:

ShowMessage((AnsiString)"a: "+licznik+"/"+mianownik);
należy umieścić:
srd::cout << "a: " << licznik << "/" << mianownik << "\n";
W tym przypadku należy pamiętać o uwzględnieniu odpowiedniej biblioteki: #include <iostream>
Wyjątkiem jest ostatnia klasa, która korzysta z AnsiString, który nie jest elementem standardowym C++.

Uwaga! (Delphi)
Kod klasy Ulamek wykorzystuje elementy Object Pascala, które zostały wprowadzone od wersji 6 (m.in przeciążanie metod). W przykładach zostały podane metody związane ze zdarzeniem Button1.OnClick. Mimot to bez większych kłopotów, po usunięciu niektórych elementów kod klasy powinien się kompilować także w Turbo Pascalu.

Uwaga! (Java)

  • Przykłady ilustrujące wykorzystanie klasy Ulamek wymagają umieszczenia na formie obiektu java.awt.List (w JBuilderze komponent ten znajduje się na zakładce AWT). Jeżeli aplet korzysta z biblioteki Swing można wykorzystać statyczną metodę JOptionPane.showMessageDialog(this, "Tekst komunikatu");
  • Przykłady umieszczone w źródłach zostały napisane za pomocą JBuilder 6 Personal, ale można je również skompilować niezależnie (niezbędny jest wówczas Java Development Kit (JDK), który można ściągnąć ze strony http://java.sun.com). W tym celu należy skopiować z wybranego projektu katalog zawierający cały pakiet klasy ("src\klasy"), a następnie w katalogu nadrzędnym (katalog "klasy" musi bć skopiowany jako całość, jego nazwa musi być zachowana) uruchomić kompilator poleceniem (zazwyczaj niezbędne jest podanie pełnej ścieżki do javac.exe lub dopisanie jej do zmiennej środowiskowej PATH):
    javac klasy\*.java
    Aplikację można teraz uruchomić wpisując:
    java klasy.Application1
    Można się posunąć o krok dalej i stworzyć pojedynczy plik wykonywalny jar. Należy przygotować prosty plik (np. "klasyManifest") zawierający nazwę wykonywalnej klasy w jednej linii zakończonej znakiem końca linii (w naszym przypadku linia ta powinna zawierać: Main-Class: klasy.Application1). Teraz można spakować skompilowane klasy poleceniem:
    jar cmf klasyManifest klasy.jar klasy\*.class
    i uruchomić je klikając w Windows Explorerze dwukrotnie myszką na plik klasy.jar lub wpisując:
    java -jar klasy.jar

    Uwaga!
    W przypadku wszystkich przykładów najlepiej na formie umieścić przycisk i wkleić kod do ich metod zdarzeniowych związanych z jego przyciśnięciem.

     


    Deklaracja klasy, pola:

    C++
    class ulamek
    	{
        private:
        	int licznik, mianownik;
        };
    
    Java (plik Ulamek.java)
    public class Ulamek 
    {
    	private int licznik,mianownik;
    }
    
    Delphi
    interface
    
    type
    ulamek = class
    	private
        	licznik,mianownik :Integer;
        end;
    
    C#
    public class Ulamek
    {
    	private int licznik,mianownik;
    }
    
    Przykład kodu:
    ulamek a;
    ulamek* b=new ulamek();
    
    delete b;
    
    Przykład kodu:
    Ulamek a=new Ulamek();
    
    Przykład kodu:
    procedure TForm1.Button1Click(Sender: TObject);
    var a :Ulamek;
    
    begin
    a:=Ulamek.Create;
    a.Free;
    end;
    
    Przykład kodu:
    Ulamek a=new Ulamek();
    

    Uwagi!


    Deklaracja klasy, metody:

    1. Definicja klasy - słowo kluczowe class i blok następujący bespośrednio za nim: class {...}
    2. Deklaracja klasy - zbiór metod określonych poza definicją klasy.
      Uwaga! Funkcje zadeklarowane w obrębie definicji klasy są zawsze inline, co oznacza, że są włączane do kodu binarnego w każdym miejscu wywołania metody i nie podlegają optymalizacji.
    3. Interface klasy - część publiczna klasy, służąca do komunikacji z innymi obiektami i elementami kodu.
    4. Implementacja klasy - część pryatna i chroniona, która realizuje właściwe zadania klasy.
    C++
    class ulamek
    	{
    	private:
    		int licznik, mianownik;
    	public:
    		bool set(int alicznik,int amianownik)
    			{
    			if (amianownik==0) return false;
    			licznik=alicznik;
    			mianownik=amianownik;
    			return true;
    			}
    		void get(int& rlicznik,int& rmianownik) const
    			{
    			rlicznik=licznik;
    			rmianownik=mianownik;
    			}
    		void get(int* plicznik,int* pmianownik) const
    			{
    			*plicznik=licznik;
    			*pmianownik=mianownik;
    			}
    	};
    
    Java
    package klasy;
    
    /**
     * <p>Title: Ulamek</p>
     * <p>Description: Przykladowa klasa Ulamek</p>
     * <p>Copyright: Copyright (c) Jacek Matulewski 2003</p>
     * <p>Company: </p>
     * @author unascribed
     * @version 1.0
     */
    
    public class Ulamek
    {
      private int licznik,mianownik;
    
      public boolean set(int alicznik,int amianownik)
        {
        if (amianownik==0) return false;
        licznik=alicznik;
        mianownik=amianownik;
        return true;
        }
    
      public void get(int[] arg)
        {
        arg[0]=licznik;
        arg[1]=mianownik;
        }
    
      public int[] get()
        {
        int[] wynik=new int[2];
        wynik[0]=licznik;
        wynik[1]=mianownik;
        return wynik;
        }
    }
    
    Delphi
    unit _ulamek;
    
    interface
    
    type
    Ulamek = class
        private
            licznik :Integer;
            mianownik :Integer;
        public
            function SetValues(const alicznik, amianownik :Integer) :Boolean;
            procedure GetValues(var rlicznik :Integer; var rmianownik :Integer); overload;
            procedure GetValues(plicznik, pmianownik :PInteger); overload;
        end;
    
    implementation
    
    function Ulamek.SetValues(const alicznik, amianownik :Integer) :Boolean;
    begin
    if amianownik=0 then begin
                         SetValues:=False;
                         Exit;
                         end;
    licznik:=alicznik;
    mianownik:=amianownik;
    SetValues:=True;
    end;
    
    procedure Ulamek.GetValues(var rlicznik :Integer; var rmianownik :Integer);
    begin
    rlicznik:=licznik;
    rmianownik:=mianownik;
    end;
    
    procedure Ulamek.GetValues(plicznik :PInteger; pmianownik :PInteger);
    begin
    plicznik^:=licznik;
    pmianownik^:=mianownik;
    end;
    
    end.
    
    C#
    public class Ulamek
    {
    	private int licznik,mianownik;
    
    	public bool set(int alicznik,int amianownik)
    		{
    		if (amianownik==0) return false;
    		licznik=alicznik;
    		mianownik=amianownik;
    		return true;
    		}
    
    	public void get(out int rlicznik,out int rmianownik)
    		{
    		rlicznik=licznik;
    		rmianownik=mianownik;
    		}
    
    	public void get(int[] arg)
    		{
    		arg[0]=licznik;
    		arg[1]=mianownik;
    		}
    
    	public int[] get()
    		{
    		int[] wynik=new int[2];
    		wynik[0]=licznik;
    		wynik[1]=mianownik;
    		return wynik;
    		}
    }
    
    
    Przykład kodu:
    ulamek a;
    if (a.set(1,2)) ShowMessage("a,1: OK"); else ShowMessage("a,1: Blad");
    if (a.set(1,0)) ShowMessage("a,2: OK"); else ShowMessage("a,2: Blad");
    
    ulamek* b=new ulamek();
    if (b->set(3,4)) ShowMessage("b: OK"); else ShowMessage("b: Blad");
    
    int licznik,mianownik;
    a.get(licznik,mianownik);
    ShowMessage((AnsiString)"a: "+licznik+"/"+mianownik);
    
    (*b).get(&licznik,&mianownik);  //b->get() == (*b).get()
    ShowMessage((AnsiString)"b: "+licznik+"/"+mianownik);
    
    delete b;
    
    Przykład kodu:
    Ulamek a=new Ulamek();
    
    if (a.set(1,2)) list1.add("a,1: OK"); else list1.add("a,1: Blad");
    if (a.set(1,0)) list1.add("a,2: OK"); else list1.add("a,2: Blad");
    
    int[] licznik_mianownik=new int[2];
    a.get(licznik_mianownik);
    list1.add("a: "+String.valueOf(licznik_mianownik[0])+"/"+
                    String.valueOf(licznik_mianownik[1]));
    
    licznik_mianownik=a.get();
    list1.add("a: "+String.valueOf(licznik_mianownik[0])+"/"+
                    String.valueOf(licznik_mianownik[1]));
    
    Przykład kodu:
    procedure TForm1.Button1Click(Sender: TObject);
    var a,b :Ulamek;
        licznik,mianownik :Integer;
    begin
    a:=Ulamek.Create;
    if a.SetValues(1,2) then ShowMessage('a,1: OK') else ShowMessage('a,1: Blad');
    if a.SetValues(1,0) then ShowMessage('a,2: OK') else ShowMessage('a,2: Blad');
    
    b:=Ulamek.Create;
    if b.SetValues(3,4) then ShowMessage('b: OK') else ShowMessage('b: Blad');
    
    a.GetValues(licznik,mianownik);
    ShowMessage('a: '+IntToStr(licznik)+'/'+IntToStr(mianownik));
    
    b.GetValues(@licznik,@mianownik);
    ShowMessage('b: '+IntToStr(licznik)+'/'+IntToStr(mianownik));
    
    a.Free;
    b.Free;
    end;
    
    Przykład kodu:
    Ulamek a=new Ulamek();
    
    if (a.set(1,2)) MessageBox.Show("a,1: OK"); else MessageBox.Show("a,1: Blad");
    if (a.set(1,0)) MessageBox.Show("a,2: OK"); else MessageBox.Show("a,2: Blad");
    
    int licznik=0,mianownik=0;
    a.get(out licznik,out mianownik);
    MessageBox.Show("a: "+licznik+"/"+mianownik);
    
    int[] licznik_mianownik=new int[2];
    licznik_mianownik=a.get();
    MessageBox.Show("a: "+licznik_mianownik[0]+"/"+licznik_mianownik[1]);
    

    Uwaga!

    Obsługa błędów w konstruktorze klasy wykorzystująca wyjątki:

    Polecenie throw w C++ i Javie oraz raise w Delphi powoduje wysłanie wyjątku. Rezultatem jest natychmiastowe przeniesienie do sekcji catch związanego z otaczającym wystąpienie wyjątku polecenia try. Jeżeli taka sekcja nie zostanie znaleziona, lub nie przyjmuje klasy obiektu, który został przesłany jako wyjątek - wówczas obsługę wyjątku przejmuje domyślna obsługa wyjątków (w C++ Builderze jest to try ... catch otaczające Application->Run, w Javie - wywołana zostanie metoda UncaughtException). Wyjątki zastępują obsługę błędów polegającą na zwracaniu wartości logicznej przez każdą funkcję. Pozwala to na unknięcie sprawdzania wartości funkcji przy każdym jej wywołaniu, szczególnie w wywołaniach zagnieźdzonych oraz na obsługę błędów w konstruktorze, który żadnej wartości zwracać nie może.

    Najbardziej konsekwętnie obsługa wyjątków przeprowadzona została w Javie, gdzie metoda przesyłająca wyjątek musi deklarować taką możliwość w nagłówku, za nazwą i argumentami, a kompilator pozwala na wywołanie takiej metody tylko po otoczeniu przez polecenia przechwytujące wyjątki.

    Uwaga!
    Po przesłaniu wyjątku i wykonaniu bloku instrukcji zawartych w catch program nie wraca do linii następującej po wystopięniu wyjątku.

    C++
    void set(int alicznik,int amianownik)
    	{
    	if (amianownik==0) throw "Ulamek: Blad #1";
    	licznik=alicznik;
    	mianownik=amianownik;
    	}
    
    Java
    public void set(int alicznik,int amianownik)
        throws Exception
        {
        if (amianownik==0) throw new Exception("Ulamek: Blad #1");
        licznik=alicznik;
        mianownik=amianownik;
        }
    
    Pascal
    procedure Ulamek.SetValues(const alicznik, amianownik :Integer);
    begin
    if amianownik=0 then raise Exception.Create('Ulamek: Blad #1');
    licznik:=alicznik;
    mianownik:=amianownik;
    end;
    
    C#
    public void set(int alicznik,int amianownik)
    	{
    	if (amianownik==0) throw new Exception("Ulamek: Blad #1");
    	licznik=alicznik;
    	mianownik=amianownik;
    	}
    
    Przykład kodu:
    ulamek* c=new ulamek();
    try
        {
        c->set(1,0);
        ShowMessage("c: OK");
        }
    catch(char* E) {ShowMessage(E);}
    
    int licznik,mianownik;
    c->get(licznik,mianownik);
    ShowMessage((AnsiString)"c: "+licznik+"/"+mianownik);
    
    delete c;
    
    Przykład kodu:
        Ulamek c=new Ulamek();
    
        try
          {
          c.set(1,0);
          list1.add("c: OK");
          }
        catch(Exception E)
          {
          list1.add(E.getMessage());
          }
    
    
        int[] licznik_mianownik=new int[2];
        c.get(licznik_mianownik);
        list1.add("c: "+String.valueOf(licznik_mianownik[0])+"/"+
                  String.valueOf(licznik_mianownik[1]));
    
    Przykład kodu:
    procedure TForm1.Button1Click(Sender: TObject);
    var c :Ulamek;
        licznik,mianownik :Integer;
    begin
    c:=Ulamek.Create;
    
    try
      c.SetValues(1,0);
      ShowMessage('c: OK');
    except
      on E: Exception do ShowMessage(E.Message);
    end;
    
    c.GetValues(licznik,mianownik);
    ShowMessage('c: '+IntToStr(licznik)+'/'+IntToStr(mianownik));
    
    c.Free;
    end;
    
    Przykład kodu:
    Ulamek c=new Ulamek();
    
    try //Obsluga wyjatkow w C# nie jest obowiazkowa
    {
    	MessageBox.Show("Pojawi się wyjątek, bo mianownik ustalam na 0");
    	c.set(1,0);
    	MessageBox.Show("c: OK");
    }
    catch(Exception exc)
    {
    	MessageBox.Show(exc.Message);
    }
    
    int licznik,mianownik;
    c.get(out licznik,out mianownik);
    MessageBox.Show("c: "+licznik+"/"+mianownik);
    

    Uwaga!

    Konstruktor:

    C++
    class ulamek
    	{
        private:
        	int licznik, mianownik;
        public:
        	ulamek(int alicznik,int amianownik)
                {
                set(alicznik,amianownik);
                }
        	void set(int alicznik,int amianownik)
                {
                if (amianownik==0) throw "Ulamek: Blad #1";
                licznik=alicznik;
                mianownik=amianownik;
                }
            void get(int& rlicznik,int& rmianownik) const
                {
                rlicznik=licznik;
                rmianownik=mianownik;
                }
            void get(int* plicznik,int* pmianownik) const
                {
                *plicznik=licznik;
                *pmianownik=mianownik;
                }
        };
    
    Java
    package klasy;
    
    public class Ulamek
    {
      private int licznik,mianownik;
    
      public Ulamek(int alicznik,int amianownik)
        throws Exception
        {
        try
          {
          set(alicznik,amianownik);
          }
        catch(Exception E)
          {
          throw E;
          }
        }
    
      public void set(int alicznik,int amianownik)
        throws Exception
        {
        if (amianownik==0) throw new Exception("Ulamek: Blad #1");
        licznik=alicznik;
        mianownik=amianownik;
        }
    
      public void get(int[] arg)
        {
        arg[0]=licznik;
        arg[1]=mianownik;
        }
    
      public int[] get()
        {
        int[] wynik=new int[2];
        wynik[0]=licznik;
        wynik[1]=mianownik;
        return wynik;
        }
    }
    
    Pascal
    unit _ulamek;
    
    interface
    
    uses SysUtils;
    
    type
    Ulamek = class
        private
            licznik :Integer;
            mianownik :Integer;
        public
            constructor Create(const alicznik, amianownik :Integer);
            procedure SetValues(const alicznik, amianownik :Integer);
            procedure GetValues(var rlicznik :Integer; var rmianownik :Integer); overload;
            procedure GetValues(plicznik, pmianownik :PInteger); overload;
        end;
    
    implementation
    
    constructor Ulamek.Create(const alicznik, amianownik :Integer);
    begin
    inherited Create; //TObject.Create()
    SetValues(alicznik,amianownik);
    end;
    
    procedure Ulamek.SetValues(const alicznik, amianownik :Integer);
    begin
    if amianownik=0 then raise Exception.Create('Ulamek: Blad #1');
    licznik:=alicznik;
    mianownik:=amianownik;
    end;
    
    procedure Ulamek.GetValues(var rlicznik :Integer; var rmianownik :Integer);
    begin
    rlicznik:=licznik;
    rmianownik:=mianownik;
    end;
    
    procedure Ulamek.GetValues(plicznik :PInteger; pmianownik :PInteger);
    begin
    plicznik^:=licznik;
    pmianownik^:=mianownik;
    end;
    
    end.
    
    C#
    public class Ulamek
    {
    	private int licznik,mianownik;
    
    	public Ulamek(int alicznik,int amianownik)
    	{
    		set(alicznik,amianownik);
    	}
    
    	public void set(int alicznik,int amianownik)
    	{
    		if (amianownik==0) throw new Exception("Ulamek: Blad #1");
    		licznik=alicznik;
    		mianownik=amianownik;
    	}
    
    	public void get(out int rlicznik,out int rmianownik)
    	{
    		rlicznik=licznik;
    		rmianownik=mianownik;
    	}		
    
    	public void get(int[] arg)
    	{
    		arg[0]=licznik;
    		arg[1]=mianownik;
    	}
    
    	public int[] get()
    	{
    		int[] wynik=new int[2];
    		wynik[0]=licznik;
    		wynik[1]=mianownik;
    		return wynik;
    	}
    }
    
    Przykład kodu:
    ulamek a(1,2);
    ulamek* b=new ulamek(3,4);
    
    delete b;
    
    Przykład kodu:
    Ulamek a=null,b=null,c=null;
    try
      {
      a=new Ulamek(1,2);
      b=new Ulamek(3,4);
      c=new Ulamek(1,0);
      }
    catch(Exception E)
      {
      list1.add(E.getMessage());
      }
    
    int[] licznik_mianownik=new int[2];
    a.get(licznik_mianownik);
    list1.add("a: "+String.valueOf(licznik_mianownik[0])+"/"+
                    String.valueOf(licznik_mianownik[1]));
    b.get(licznik_mianownik);
    list1.add("b: "+String.valueOf(licznik_mianownik[0])+"/"+
                    String.valueOf(licznik_mianownik[1]));
    c.get(licznik_mianownik);
    list1.add("c: "+String.valueOf(licznik_mianownik[0])+"/"+
                    String.valueOf(licznik_mianownik[1]));
    
    Przykład kodu:
    procedure TForm1.Button1Click(Sender: TObject);
    var a :Ulamek;
        licznik,mianownik :Integer;
    begin
    a:=Ulamek.Create(1,2);
    a.Free;
    end;
    
    Przykład kodu:
    Ulamek a=new Ulamek(1,2);
    
    int licznik,mianownik;
    a.get(out licznik,out mianownik);
    MessageBox.Show("a: "+licznik+"/"+mianownik);
    

    Uwaga!


    Własne klasy wyjatkow:

    Wyjątek - obiekt zawierający informację o sytuacji krytycznej, który jest przesyłany poleceniem throw po jej wystąpieniu. Wyjątek może być przechwycony jeżeli miejsce jego wystąpienia otoczone jest przez try {...} catch() {...}. Wówczas wykonywany jest kod znajdujący się w bloku następującym po catch, a następnie kod znajdujący się za nim (program nie wraca do poleceń znajdujących się za throw. W standardzie C++ znajduje się domyślny obiekt wyjątku std::exception (VCL posiada własny Exception), ale można też napisać własną klasę lub przesyłać, jak w poprzednim przykładzie dotyczącym wyjątków, np. tablicę znaków.

    C++
    class ulamek_exception
        {
        private:
        	char* message;
        public:
    		ulamek_exception(char* amessage) {message=amessage;};
    		char* what() const {return message;};
        };
    
    
    class ulamek
        {
        private:
        	int licznik, mianownik;
        public:
        	ulamek(int alicznik=0,int amianownik=1)
                {
                set(alicznik,amianownik);
                }
        	void set(int alicznik,int amianownik)
                {
                if (amianownik==0) throw ulamek_exception("Ulamek: Blad #1");
                licznik=alicznik;
                mianownik=amianownik;
                }
            void get(int& rlicznik,int& rmianownik) const
                {
                rlicznik=licznik;
                rmianownik=mianownik;
                }
            void get(int* plicznik,int* pmianownik) const
                {
                *plicznik=licznik;
                *pmianownik=mianownik;
                }
        };
    
    Java
    package klasy;
    
    class Ulamek_Exception extends Exception
    {
      private String message;
      public Ulamek_Exception(String amessage) {message=amessage;}
      public String what() {return message;}
    }
    
    public class Ulamek
    {
      private int licznik,mianownik;
    
      public Ulamek(int alicznik,int amianownik)
        throws Ulamek_Exception
        {
        try
          {
          set(alicznik,amianownik);
          }
        catch(Ulamek_Exception E)
          {
          throw E;
          }
        }
    
      public void set(int alicznik,int amianownik)
        throws Ulamek_Exception
        {
        if (amianownik==0) throw new Ulamek_Exception("Ulamek: Blad #1");
        licznik=alicznik;
        mianownik=amianownik;
        }
    
      public void int[] arg)
        {
        arg[0]=licznik;
        arg[1]=mianownik;
        }
    
      public int[] get()
        {
        int[] wynik=new int[2];
        wynik[0]=licznik;
        wynik[1]=mianownik;
        return wynik;
        }
    }
    
    Pascal
    unit _ulamek;
    
    interface
    
    uses SysUtils;
    
    type
    Ulamek_Exception = class(Exception)
        private
            Message :String;
        public
            constructor Create(const AMessage :String);
            function What :String;
        end;
    
    Ulamek = class
        private
            licznik :Integer;
            mianownik :Integer;
        public
            constructor Create(const alicznik :Integer =0; const amianownik :Integer =1);
            procedure SetValues(const alicznik, amianownik :Integer);
            procedure GetValues(var rlicznik :Integer; var rmianownik :Integer); overload;
            procedure GetValues(plicznik, pmianownik :PInteger); overload;
        end;
    
    function IntToUlamek(const liczba :Integer) :Ulamek;
    
    implementation
    
    constructor Ulamek_Exception.Create(const AMessage :String);
    begin
    Message:=AMessage;
    end;
    
    function Ulamek_Exception.What :String;
    begin
    What:=Message;
    end;
    
    
    constructor Ulamek.Create(const alicznik :Integer =0; const amianownik :Integer =1);
    begin
    inherited Create;
    SetValues(alicznik,amianownik);
    end;
    
    procedure Ulamek.SetValues(const alicznik, amianownik :Integer);
    begin
    if amianownik=0 then raise Ulamek_Exception.Create('Ulamek: Blad #1');
    licznik:=alicznik;
    mianownik:=amianownik;
    end;
    
    procedure Ulamek.GetValues(var rlicznik :Integer; var rmianownik :Integer);
    begin
    rlicznik:=licznik;
    rmianownik:=mianownik;
    end;
    
    procedure Ulamek.GetValues(plicznik :PInteger; pmianownik :PInteger);
    begin
    plicznik^:=licznik;
    pmianownik^:=mianownik;
    end;
    
    
    //FUNKCJA KONWERTUJACA
    function IntToUlamek(const liczba :Integer) :Ulamek;
    begin
    IntToUlamek:=Ulamek.Create(liczba,1);
    end;
    
    end.
    
    C#
    class Ulamek_Exception : Exception
    {
    	private String message;
    	public Ulamek_Exception(String amessage) {message=amessage;}
    	public String what() {return message;}
    }
    
    public class Ulamek
    {
    	private int licznik,mianownik;
    
    	public Ulamek(int alicznik,int amianownik)
    		{
    		set(alicznik,amianownik);
    		}
    
    	public void set(int alicznik,int amianownik)
    		{
    		if (amianownik==0) throw new Ulamek_Exception("Ulamek: Blad #1");
    		licznik=alicznik;
    		mianownik=amianownik;
    		}
    
    	public void get(out int rlicznik,out int rmianownik)
    		{
    		rlicznik=licznik;
    		rmianownik=mianownik;
    		}		
    
    	public void get(int[] arg)
    		{
    		arg[0]=licznik;
    		arg[1]=mianownik;
    		}
    
    	public int[] get()
    		{
    		int[] wynik=new int[2];
    		wynik[0]=licznik;
    		wynik[1]=mianownik;
    		return wynik;
    		}
    }
    
    Przykład kodu:
    ulamek* c=NULL;
    try
        {
        c=new ulamek(1,0);
        }
    catch(ulamek_exception& E)
        {
        ShowMessage(E.what());
        c=NULL;
        }
    
    if (c!=NULL)
        {
        c->get(licznik,mianownik);
        ShowMessage((AnsiString)"c: "+licznik+"/"+mianownik);
        delete c;
        }
    
    Przykład kodu:
    Ulamek a=null,b=null,c=null;
    try
      {
      a=new Ulamek(1,2);
      b=new Ulamek(3,4);
      c=new Ulamek(1,0);
      }
    catch(Ulamek_Exception E)
      {
      list1.add(E.what());
      }
    
    int[] licznik_mianownik=new int[2];
    a.get(licznik_mianownik);
    list1.add("a: "+String.valueOf(licznik_mianownik[0])+"/"+
                    String.valueOf(licznik_mianownik[1]));
    b.get(licznik_mianownik);
    list1.add("b: "+String.valueOf(licznik_mianownik[0])+"/"+
                    String.valueOf(licznik_mianownik[1]));
    c.get(licznik_mianownik);
    list1.add("c: "+String.valueOf(licznik_mianownik[0])+"/"+
                    String.valueOf(licznik_mianownik[1]));
    
    Przykład kodu:
    procedure TForm1.Button1Click(Sender: TObject);
    var c :Ulamek;
    begin
        try
            c:=Ulamek.Create(1,0);
        except
            on E :Ulamek_Exception do ShowMessage(E.What);
        end;
    end;
    
    Przykład kodu:
    Ulamek a=null,b=null,c=null;
    try
    {
    	a=new Ulamek(1,2);
    	b=new Ulamek(3,4);
    	c=new Ulamek(1,0);
    }
    catch(Ulamek_Exception E)
    {
    	MessageBox.Show(E.what());
    }
    
    int licznik,mianownik;
    a.get(out licznik,out mianownik);
    MessageBox.Show("a: "+licznik+"/"+mianownik);
    
    b.get(out licznik,out mianownik);
    MessageBox.Show("b: "+licznik+"/"+mianownik);
    
    c.get(out licznik,out mianownik);
    MessageBox.Show("c: "+licznik+"/"+mianownik);
    

    Uwaga!
    Po przesłaniu wyjątku program nie wraca do dalszych linii następujących po throw.


    Konstruktor copy:

    1. Konstruktor kopiujący jest tworzony przez kompilator i poza rzadkimi wypadkami, gdy podczas kopiowania pól będących wskaźnikami chcemy tworzyć odrębną instancję wskazywanego przez ten adres obiektu, nie ma najmniejszego uzasadnienia do jego własnoręcznego pisania.
    2. Kontruktor kopiujący jest wykorzystywany podczas inicjowania obiektu, a więc w naszym przypadku może to być: ulamek b=a (a jest obiektem klasy ulamek) lub przy tworzeniu instancji obiektu przy przesyłaniu go jako argument funkcji.
    3. Nie nalezy mylic sytuacji, w której wykorzystywany jest konstruktor copy ze zwyklym wykorzystaniem operatora przypisania =, np. b=a (przy wcześniejszym zadeklarowaniu i zainicjowaniu obiektów a i b np. jako ulamek a(1,2), b(3,4);).

    W Javie zastąpiłem przykład konstruktora kopiującego, który w tym języku nie występuje, przykładem wykorzystania metody clone(), który przejmuje niektóre jego funkcje. Podobnie w C#, w której zdefiniowana została metoda Clone().

    C++
    class ulamek
        {
        private:
        	int licznik, mianownik;
        public:
        	ulamek(int alicznik=0,int amianownik=1)
                {
                set(alicznik,amianownik);
                }
        	ulamek(const ulamek& aulamek)
                {
                aulamek.get(licznik,mianownik);
                }
        	void set(int alicznik,int amianownik)
                {
                if (amianownik==0) throw "Ulamek: Blad #1";
                licznik=alicznik;
                mianownik=amianownik;
                }
            void get(int& rlicznik,int& rmianownik) const
                {
                rlicznik=licznik;
                rmianownik=mianownik;
                }
            void get(int* plicznik,int* pmianownik) const
                {
                *plicznik=licznik;
                *pmianownik=mianownik;
                }
        };
    
    Java
    package klasy;
    
    public class Ulamek implements Cloneable
    {
      private int licznik,mianownik;
    
      public Ulamek(int alicznik,int amianownik)
        throws Exception
        {
        try
          {
          set(alicznik,amianownik);
          }
        catch(Exception E)
          {
          throw E;
          }
        }
    
      public Object clone()
        throws CloneNotSupportedException
        {
        Object wynik=null;
        try
          {
          wynik=super.clone();
          }
        catch(CloneNotSupportedException E)
          {
          throw E;
          }
        return wynik;
        }
    
      public void set(int alicznik,int amianownik)
        throws Exception
        {
        if (amianownik==0) throw new Exception("Ulamek: Blad #1");
        licznik=alicznik;
        mianownik=amianownik;
        }
    
      public void get(int[] arg)
        {
        arg[0]=licznik;
        arg[1]=mianownik;
        }
    
      public int[] get()
        {
        int[] wynik=new int[2];
        wynik[0]=licznik;
        wynik[1]=mianownik;
        return wynik;
        }
    }
    
    Pascal
    
            
    C#
    public class Ulamek
    {
    	private int licznik,mianownik;
    
    	public Ulamek(int alicznik,int amianownik)
    		{
    		set(alicznik,amianownik);
    		}
    
    	//cos podobnego do konstruktora copy w C++
    	public Ulamek(Ulamek aulamek)
    		{
    		int olicznik,omianownik;
    		aulamek.get(out olicznik,out omianownik);
    		set(olicznik,omianownik);
    		}
    
    	//analog funkcji clone() w Javie
    	public Ulamek Clone()
    		{
    		return new Ulamek(licznik,mianownik);
    		}
    
    	public void set(int alicznik,int amianownik)
    		{
    		if (amianownik==0) throw new Ulamek_Exception("Ulamek: Blad #1");
    		licznik=alicznik;
    		mianownik=amianownik;
    		}
    
    	public void get(out int rlicznik,out int rmianownik)
    		{
    		rlicznik=licznik;
    		rmianownik=mianownik;
    		}		
    
    	public void get(int[] arg)
    		{
    		arg[0]=licznik;
    		arg[1]=mianownik;
    		}
    
    	public int[] get()
    		{
    		int[] wynik=new int[2];
    		wynik[0]=licznik;
    		wynik[1]=mianownik;
    		return wynik;
    		}
    }
    
    Przykład kodu
    ulamek a(1,2); //konstruktor
    ulamek c(a); //konstruktor copy 
    ulamek b=a; //konstruktor copy
    a.set(3,4); //zmiana stanu pierwotnego obiektu
    c=b; //operator przypisania =
    
    Przykład kodu:
    Ulamek a=null,b=null,c=null;
    try
      {
      a=new Ulamek(1,2);
      b=new Ulamek(3,4);
      c=(Ulamek)a.clone();
      a.set(3,4);
      }
    catch(CloneNotSupportedException CloneE)
      {
      list1.add(CloneE.getMessage());
      }
    catch(Exception E)
      {
      list1.add(E.getMessage());
      }
    
    int[] licznik_mianownik=new int[2];
    a.get(licznik_mianownik);
    list1.add("a: "+String.valueOf(licznik_mianownik[0])+"/"+
                    String.valueOf(licznik_mianownik[1]));
    b.get(licznik_mianownik);
    list1.add("b: "+String.valueOf(licznik_mianownik[0])+"/"+
                    String.valueOf(licznik_mianownik[1]));
    c.get(licznik_mianownik);
    list1.add("c: "+String.valueOf(licznik_mianownik[0])+"/"+
                    String.valueOf(licznik_mianownik[1]));
    
    Pascal
    
            
    Przykład kodu:
    Ulamek a=null,b=null,c=null;
    
    try
    {
    	a=new Ulamek(1,2);
    	c=new Ulamek(a);
    
    	b=a;
    	a.set(3,4);
    	//c=b;
    }
    catch(Ulamek_Exception E)
    {
    	MessageBox.Show(E.what());
    }
    
    int licznik,mianownik;
    a.get(out licznik,out mianownik);
    MessageBox.Show("a: "+licznik+"/"+mianownik);
    
    b.get(out licznik,out mianownik);
    MessageBox.Show("b: "+licznik+"/"+mianownik);
    
    c.get(out licznik,out mianownik);
    MessageBox.Show("c: "+licznik+"/"+mianownik);
    

    Uwaga!


    Obiekty stałe:

    C++
    const ulamek ulamek_zero(0,1);
    const ulamek ulamek_jeden(1,1);
    const ulamek ulamek_polowa(1,2);
    const ulamek ulamek_cwierc(1,4);
    
    Przykład kodu
    ulamek a=ulamek_polowa;
    ulamek b(ulamek_cwierc);
    

    Uwaga!


    Działania określone dla klasy, operatory:

    Działania na ułamkach (ew. na ułamkach i liczbach całkowitych) powinny zwracać ułamek. Należy więc zdefiniować odpowiednie operatory implementujące odpowiednie działania arytmetyczne: +(u,u), -(u), -(u,u), *(u,u), /(u,u), a ponadto <(u,u) oraz >(u,u). Ostatnie dwa zwracają wartość logiczną.

    Istnieją dwie możliwości tworzenia operatorów: pierwsza to operator będący elementem klasy (daje to pewne korzyści przy ewentualnym dziedziczeniu), druga to niezależny operator zdefiniowany dla jednego lub dwóch argumentów odpowiedniej klasy. Korzyścią drugiego sposobu jest rozciągnięcie niejawnej konwersji również na pierwszy argument, który w pierwszym przypadku musi być jawnie typu odpowiednij klasy.

    W Pascalu i Javie o definiowaniu operatorów nie ma co śnić (jedyny przeciążony operator to + dla klasy String) - wzamian zdefiniujemy funkcje. W Javie funkcje mogą być wyłącznie metodami, tj. muszą być związane z jakąś klasą, ale mogą być metodami statycznymi tj. nie wymagającymi do ich uruchomienia stworzenia obiektu.

    C++
    ulamek operator *(const ulamek& aulamek1,const ulamek& aulamek2)
        {
        int alicznik1=0,amianownik1=1;aulamek1.get(alicznik1,amianownik1);
        int alicznik2=0,amianownik2=1;aulamek2.get(alicznik2,amianownik2);
        return ulamek(alicznik1*alicznik2,amianownik1*amianownik2);
        };
    ulamek operator /(const ulamek& aulamek1,const ulamek& aulamek2)
        {
        int alicznik1=0,amianownik1=1;aulamek1.get(alicznik1,amianownik1);
        int alicznik2=0,amianownik2=1;aulamek2.get(alicznik2,amianownik2);
        return ulamek(alicznik1*amianownik2,amianownik1*alicznik2);
        };
    ulamek operator +(const ulamek& aulamek1,const ulamek& aulamek2)
        {
        int alicznik1=0,amianownik1=1;aulamek1.get(alicznik1,amianownik1);
        int alicznik2=0,amianownik2=1;aulamek2.get(alicznik2,amianownik2);
        return ulamek(alicznik1*amianownik2+alicznik2*amianownik1,amianownik1*amianownik2);
        };
    ulamek operator -(const ulamek& aulamek1)
        {
        int alicznik1=0,amianownik1=1;aulamek1.get(alicznik1,amianownik1);
        return ulamek(-alicznik1,amianownik1);
        };
    ulamek operator -(const ulamek& aulamek1,const ulamek& aulamek2)
        {
        int alicznik1=0,amianownik1=1;aulamek1.get(alicznik1,amianownik1);
        int alicznik2=0,amianownik2=1;aulamek2.get(alicznik2,amianownik2);
        return ulamek(alicznik1*amianownik2-alicznik2*amianownik1,amianownik1*amianownik2);
        };
    bool operator <(const ulamek& aulamek1,const ulamek& aulamek2)
        {
        int alicznik1=0,amianownik1=1;aulamek1.get(alicznik1,amianownik1);
        int alicznik2=0,amianownik2=1;aulamek2.get(alicznik2,amianownik2);
        return (alicznik1/(double)amianownik1)<(alicznik2/(double)amianownik2);
        };
    bool operator >(const ulamek& aulamek1,const ulamek& aulamek2)
        {
        int alicznik1=0,amianownik1=1;aulamek1.get(alicznik1,amianownik1);
        int alicznik2=0,amianownik2=1;aulamek2.get(alicznik2,amianownik2);
        return (alicznik1/(double)amianownik1)>(alicznik2/(double)amianownik2);
        };
    bool operator ==(const ulamek& aulamek1,const ulamek& aulamek2)
        {
        int alicznik1=0,amianownik1=1;aulamek1.get(alicznik1,amianownik1);
        int alicznik2=0,amianownik2=1;aulamek2.get(alicznik2,amianownik2);
        return (alicznik1/(double)amianownik1)==(alicznik2/(double)amianownik2);
        };
    
    Java
    public static Ulamek Prod(Ulamek aulamek1,Ulamek aulamek2)
      throws Exception
      {
      int[] alicznik1_amianownik1=aulamek1.get();
      int[] alicznik2_amianownik2=aulamek2.get();
      Ulamek wynik=null;
      try
        {
        wynik=new Ulamek(alicznik1_amianownik1[0]*alicznik2_amianownik2[0],
    	                 alicznik1_amianownik1[1]*alicznik2_amianownik2[1]);
        }
      catch(Exception E) {throw E;}
      return wynik;
      }
    
    public static Ulamek Quot(Ulamek aulamek1,Ulamek aulamek2)
      throws Exception
      {
      int[] alicznik1_amianownik1=aulamek1.get();
      int[] alicznik2_amianownik2=aulamek2.get();
      Ulamek wynik=null;
      try
        {
        wynik=new Ulamek(alicznik1_amianownik1[0]*alicznik2_amianownik2[1],
    	                 alicznik1_amianownik1[1]*alicznik2_amianownik2[0]);
        }
      catch(Exception E) {throw E;}
      return wynik;
      }
    
    public static Ulamek Sum(Ulamek aulamek1,Ulamek aulamek2)
      throws Exception
      {
      int[] alicznik1_amianownik1=aulamek1.get();
      int[] alicznik2_amianownik2=aulamek2.get();
      Ulamek wynik=null;
      try
        {
        wynik=new Ulamek(alicznik1_amianownik1[0]*alicznik2_amianownik2[1]
    	                 +alicznik1_amianownik1[1]*alicznik2_amianownik2[0],
    	                 alicznik1_amianownik1[1]*alicznik2_amianownik2[1]);
        }
      catch(Exception E) {throw E;}
      return wynik;
      }
    
    public static Ulamek Revr(Ulamek aulamek1)
      throws Exception
      {
      int[] alicznik1_amianownik1=aulamek1.get();
      Ulamek wynik=null;
      try
        {
        wynik=new Ulamek(-alicznik1_amianownik1[0],alicznik1_amianownik1[1]);
        }
      catch(Exception E) {throw E;}
      return wynik;
      }
    
    public static Ulamek Diff(Ulamek aulamek1,Ulamek aulamek2)
      throws Exception
      {
      int[] alicznik1_amianownik1=aulamek1.get();
      int[] alicznik2_amianownik2=aulamek2.get();
      Ulamek wynik=null;
      try
        {
        wynik=new Ulamek(alicznik1_amianownik1[0]*alicznik2_amianownik2[1]
    	                 -alicznik1_amianownik1[1]*alicznik2_amianownik2[0],
    	                 alicznik1_amianownik1[1]*alicznik2_amianownik2[1]);
        }
      catch(Exception E) {throw E;}
      return wynik;
      }
    
    /* porownanie <, >, = */
    public static int Cmp(Ulamek aulamek1,Ulamek aulamek2)
      {
      int[] alicznik1_amianownik1=aulamek1.get();
      int[] alicznik2_amianownik2=aulamek2.get();
      double wynik=(alicznik1_amianownik1[0]/(double)alicznik1_amianownik1[1])
                   -(alicznik2_amianownik2[0]/(double)alicznik2_amianownik2[1]);
      byte int_wynik;
      if (wynik==0) int_wynik=(byte)(wynik); else int_wynik=(byte)(wynik/Math.abs(wynik));
      return int_wynik;
      }
    
    Pascal
    {iloczyn}
    function UlamekProd(const AUlamek1, AUlamek2 :Ulamek) :Ulamek;
    var alicznik1,amianownik1,alicznik2,amianownik2 :Integer;
    begin
    AUlamek1.GetValues(alicznik1,amianownik1);
    AUlamek2.GetValues(alicznik2,amianownik2);
    UlamekProd:=Ulamek.Create(alicznik1*alicznik2,amianownik1*amianownik2);
    end;
    
    {iloraz}
    function UlamekQuot(const AUlamek1, AUlamek2 :Ulamek) :Ulamek;
    var alicznik1,amianownik1,alicznik2,amianownik2 :Integer;
    begin
    AUlamek1.GetValues(alicznik1,amianownik1);
    AUlamek2.GetValues(alicznik2,amianownik2);
    UlamekQuot:=Ulamek.Create(alicznik1*amianownik2,amianownik1*alicznik2);
    end;
    
    {suma}
    function UlamekSum(const AUlamek1, AUlamek2 :Ulamek) :Ulamek;
    var alicznik1,amianownik1,alicznik2,amianownik2 :Integer;
    begin
    AUlamek1.GetValues(alicznik1,amianownik1);
    AUlamek2.GetValues(alicznik2,amianownik2);
    UlamekSum:=Ulamek.Create(alicznik1*amianownik2+alicznik2*amianownik1,amianownik1*amianownik2);
    end;
    
    {zmiana znaku}
    function UlamekRevr(const AUlamek1 :Ulamek) :Ulamek;
    var alicznik1,amianownik1 :Integer;
    begin
    AUlamek1.GetValues(alicznik1,amianownik1);
    UlamekRevr:=Ulamek.Create(-alicznik1,amianownik1);
    end;
    
    {roznica}
    function UlamekDiff(const AUlamek1, AUlamek2 :Ulamek) :Ulamek;
    var alicznik1,amianownik1,alicznik2,amianownik2 :Integer;
    begin
    AUlamek1.GetValues(alicznik1,amianownik1);
    AUlamek2.GetValues(alicznik2,amianownik2);
    UlamekDiff:=Ulamek.Create(alicznik1*amianownik2-alicznik2*amianownik1,amianownik1*amianownik2);
    end;
    
    {porownanie <, >, =}
    function UlamekCmp(const AUlamek1, AUlamek2 :Ulamek) :Integer;
    var alicznik1,amianownik1,alicznik2,amianownik2 :Integer;
        wynik :Double;
        int_wynik :Integer;
    begin
    AUlamek1.GetValues(alicznik1,amianownik1);
    AUlamek2.GetValues(alicznik2,amianownik2);
    wynik:=(alicznik1/amianownik1)-(alicznik1/amianownik2);
    if wynik=0 then int_wynik:=Round(wynik) else int_wynik:=Round(wynik/abs(wynik));
    UlamekCmp:=int_wynik;
    end;
    
    C#
    public static Ulamek operator *(Ulamek aulamek1,Ulamek aulamek2)
    	{
    	int alicznik1,amianownik1;aulamek1.get(out alicznik1,out amianownik1);
    	int alicznik2,amianownik2;aulamek2.get(out alicznik2,out amianownik2);
    	return new Ulamek(alicznik1*alicznik2,amianownik1*amianownik2);
    	}
    
    public static Ulamek operator /(Ulamek aulamek1,Ulamek aulamek2)
    	{
    	int alicznik1,amianownik1;aulamek1.get(out alicznik1,out amianownik1);
    	int alicznik2,amianownik2;aulamek2.get(out alicznik2,out amianownik2);
    	return new Ulamek(alicznik1*amianownik2,amianownik1*alicznik2);
    	}
    
    public static Ulamek operator +(Ulamek aulamek1,Ulamek aulamek2)
    	{
    	int alicznik1,amianownik1;aulamek1.get(out alicznik1,out amianownik1);
    	int alicznik2,amianownik2;aulamek2.get(out alicznik2,out amianownik2);
    	return new Ulamek(alicznik1*amianownik2+alicznik2*amianownik1,amianownik1*amianownik2);
    	}
    
    public static Ulamek operator -(Ulamek aulamek1)
    	{
    	int alicznik1,amianownik1;aulamek1.get(out alicznik1,out amianownik1);
    	return new Ulamek(-alicznik1,amianownik1);
    	}
    
    public static Ulamek operator -(Ulamek aulamek1,Ulamek aulamek2)
    	{
    	int alicznik1,amianownik1;aulamek1.get(out alicznik1,out amianownik1);
    	int alicznik2,amianownik2;aulamek2.get(out alicznik2,out amianownik2);
    	return new Ulamek(alicznik1*amianownik2-alicznik2*amianownik1,amianownik1*amianownik2);
    	}
    
    public static bool operator <(Ulamek aulamek1,Ulamek aulamek2)
    	{
    	int alicznik1,amianownik1;aulamek1.get(out alicznik1,out amianownik1);
    	int alicznik2,amianownik2;aulamek2.get(out alicznik2,out amianownik2);
    	return (alicznik1/(double)amianownik1)<(alicznik2/(double)amianownik2);
    	}
    
    public static bool operator >(Ulamek aulamek1,Ulamek aulamek2)
    	{
    	int alicznik1,amianownik1;aulamek1.get(out alicznik1,out amianownik1);
    	int alicznik2,amianownik2;aulamek2.get(out alicznik2,out amianownik2);
    	return (alicznik1/(double)amianownik1)>(alicznik2/(double)amianownik2);
    	}
    
    public override bool Equals(object obj)
    	{
    	if (obj==null) return false;
    	Ulamek aulamek2=(Ulamek)obj;
    	int alicznik2,amianownik2;aulamek2.get(out alicznik2,out amianownik2);
    	return (licznik/(double)mianownik)==(alicznik2/(double)amianownik2);
    	}
    
    public override int GetHashCode()
    	{
    	return licznik^mianownik;
    	}
    
    public static bool operator ==(Ulamek aulamek1,Ulamek aulamek2)
    	{
    	return aulamek1.Equals((Object)aulamek2);
    	}
    
    public static bool operator !=(Ulamek aulamek1,Ulamek aulamek2)
    	{
    	return !(aulamek1.Equals((Object)aulamek2));
    	}
    
    Przykład kodu
    ulamek a=ulamek_polowa;
    ulamek b(ulamek_cwierc);
    
    ulamek c=a*b;
    ulamek d(2*c);
    
    c=a/b/2;
    d=2/a;
    
    c=a+b-2;
    d=2-(-a);
    
    try {c=a/ulamek_zero;} catch(char* E) {ShowMessage(E);}
    try {d=a/0;} catch(char* E) {ShowMessage(E);}
    
    if (a<b) ShowMessage("a < b"); else ShowMessage("a >= b");
    if (a<1) ShowMessage("a < 1"); else ShowMessage("a >= 1");
    if (0<a) ShowMessage("a > 0"); else ShowMessage("a <= 0"); 
    
    if (b>a) ShowMessage("a < b"); else ShowMessage("a >= b");
    if (1>a) ShowMessage("a < 1"); else ShowMessage("a >= 1");
    if (a>0) ShowMessage("a > 0"); else ShowMessage("a <= 0");
    
    if (a==b) ShowMessage("a = b"); else ShowMessage("a != b");
    if (a==1) ShowMessage("a = 1"); else ShowMessage("a != 1");
    if (a==0) ShowMessage("a = 0"); else ShowMessage("a != 0");
    
    
    Przykład kodu:
    Ulamek a=null,b=null,c=null,d=null;
    try
      {
      a=new Ulamek(1,2);
      b=new Ulamek(3,4);
    
      c=Ulamek.Prod(a,b);
      d=Ulamek.Prod(a,new Ulamek(2,1));
    
      c=Ulamek.Quot(a,b);
      d=Ulamek.Quot(new Ulamek(2,1),a);
    
      c=Ulamek.Sum(Ulamek.Sum(a,b),new Ulamek(2,1));
      d=Ulamek.Diff(new Ulamek(2,1),Ulamek.Revr(a));
      }
    catch(Exception E)
      {
      list1.add(E.getMessage());
      }
    	
    int[] licznik_mianownik=new int[2];
    a.get(licznik_mianownik);
    list1.add("a: "+String.valueOf(licznik_mianownik[0])+"/"+
                    String.valueOf(licznik_mianownik[1]));
    b.get(licznik_mianownik);
    list1.add("b: "+String.valueOf(licznik_mianownik[0])+"/"+
                    String.valueOf(licznik_mianownik[1]));
    c.get(licznik_mianownik);
    list1.add("c: "+String.valueOf(licznik_mianownik[0])+"/"+
                    String.valueOf(licznik_mianownik[1]));
    d.get(licznik_mianownik);
    list1.add("d: "+String.valueOf(licznik_mianownik[0])+"/"+
                    String.valueOf(licznik_mianownik[1]));
    
    switch (Ulamek.Cmp(a,b))
      {
      case -1: list1.add("a < b"); break;
      case  0: list1.add("a = b"); break;
      case  1: list1.add("a > b"); break;
      default: list1.add("Blad");
      }
    
    
    
    Pascal
    procedure TForm1.Button1Click(Sender: TObject);
    var a,b,c,d :Ulamek;
        licznik,mianownik :Integer;
    begin
    a:=Ulamek.Create(1,2);
    b:=Ulamek.Create(1,4);
    
    c:=UlamekProd(a,b);
    d:=UlamekProd(IntToUlamek(2),c);
    
    c:=UlamekQuot(UlamekQuot(a,b),IntToUlamek(2));
    d:=UlamekQuot(IntToUlamek(2),c);
    
    c:=UlamekDiff(UlamekSum(a,b),IntToUlamek(2));
    d:=UlamekDiff(IntToUlamek(2),UlamekRevr(a));
    
    try
      c:=UlamekQuot(a,IntToUlamek(0));
    except
      on E: Exception do ShowMessage(E.Message);
    end;
    
    c.GetValues(licznik,mianownik);
    ShowMessage('c: '+IntToStr(licznik)+'/'+IntToStr(mianownik));
    d.GetValues(licznik,mianownik);
    ShowMessage('d: '+IntToStr(licznik)+'/'+IntToStr(mianownik));
    
    case UlamekCmp(a,b) of
      -1: ShowMessage('a < b');
       0: ShowMessage('a = b');
       1: ShowMessage('a > b');
    else
       ShowMessage('Blad');
    end;
    end;
    
    Przykład kodu:
    Ulamek a=Ulamek.Polowa;
    Ulamek b=new Ulamek(Ulamek.Cwierc);
    Ulamek c=a*b;
    
    int licznik,mianownik;
    c.get(out licznik,out mianownik);
    MessageBox.Show("c: "+licznik+"/"+mianownik);
    MessageBox.Show(a=b");
    MessageBox.Show(a==b?"a=b":"a!=b");
    

    Uwaga!


    Operatory/funkcje konwersji/rzutowania (ang. typecasting):

    C++: Korzystając z możliwości domyślnego ustalania wartości w konstruktorze dysponujemy konwersją typu int na typ ulamek. Dzięki temu nie musimy przeciążać operatorów dla liczb naturalnych i ułamków. Teraz warto zdefiniować operator konwersji z ulamek na double (konwersja na int nie ma oczywiście sensu, wiąże się bowiem z utratą informacji, ale na upartego można będzie przekonwertować ułamek na double, a potem double na int). W tym celu należy zdefiniować odpowiedni operator konwersji. Przydatna wydaje się również konwersja na łańuch znaków.

    Delphi, Java: W Object Pascalu i Javie zasady konwersji dla typów wbudowanych są ściśle określone (np. możliwe jest int->double, ale nie odwrotne). Wiele konwersji musi być jawna poprzez funkcje (np. round() dla zmiany double na int). Można rzutować także obiekty na jego typ bazowy (zawężanie) i odwrotnie (rozszerzanie). Tylko to drugie jest zawsze bezpieczne. Obiekty mogą oczywiście równiez posiadać zdefinowane przez programistę metody pozwalające na dokonanie konwersji.

    C++
    class ulamek
        {
        private:
        	int licznik, mianownik;
            double to_double()
                {
                return licznik/(double)mianownik;
                }
            char* to_string()
                {
                char str_licznik[ulamek_maxstr]; itoa(licznik,str_licznik,10);
                char str_mianownik[ulamek_maxstr]; itoa(mianownik,str_mianownik,10);
                char* str=str_licznik;
                strcat(str,"/");
                strcat(str,str_mianownik);
                return str;
                }
        public:
        	ulamek(int alicznik=0,int amianownik=1)
                {
                set(alicznik,amianownik);
                }
        	ulamek(const ulamek& aulamek)
                {
                aulamek.get(licznik,mianownik);
                }
        	void set(int alicznik,int amianownik)
                {
                if (amianownik==0) throw "Ulamek: Blad #1";
                licznik=alicznik;
                mianownik=amianownik;
                }
            void get(int& rlicznik,int& rmianownik) const
                {
                rlicznik=licznik;
                rmianownik=mianownik;
                }
            void get(int* plicznik,int* pmianownik) const
                {
                *plicznik=licznik;
                *pmianownik=mianownik;
                }
            operator double() const
                {
                return to_double();
                }        
            operator char*() const
                {
                return to_string();
                }
        };
    
    Java
    package klasy;
    
    public class Ulamek implements Cloneable
    {
      private int licznik,mianownik;
    
      public Ulamek(int alicznik,int amianownik)
        throws Exception
        {
        try
          {
          set(alicznik,amianownik);
          }
        catch(Exception E)
          {
          throw E;
          }
        }
    
      public Object clone()
        throws CloneNotSupportedException
        {
        Object wynik=null;
        try
          {
          wynik=super.clone();
          }
        catch(CloneNotSupportedException E)
          {
          throw E;
          }
        return wynik;
        }
    
      public void set(int alicznik,int amianownik)
        throws Exception
        {
        if (amianownik==0) throw new Exception("Ulamek: Blad #1");
        licznik=alicznik;
        mianownik=amianownik;
        }
    
      public void get(int[] arg)
        {
        arg[0]=licznik;
        arg[1]=mianownik;
        }
    
      public int[] get()
        {
        int[] wynik=new int[2];
        wynik[0]=licznik;
        wynik[1]=mianownik;
        return wynik;
        }
    
      /* POMINIĘTE FUNKCJE DZIAŁAŃ ARYTMETYCZNYCH I PORÓWNANIA WARTOŚCI */
    
      public double toDouble()
        {
        return licznik/(double)mianownik;
        }
    
      //nadpisana na Object.toString()
      public String toString()
        {
        return String.valueOf(licznik)+"/"+String.valueOf(mianownik);
        }
    
    }
    
    Pascal
    unit _ulamek;
    
    interface
    
    uses SysUtils;
    
    type
    Ulamek_Exception = class(Exception)
        private
            Message :String;
        public
            constructor Create(const AMessage :String);
            function What :String;
        end;
    
    Ulamek = class
        private
            licznik :Integer;
            mianownik :Integer;
        public
            constructor Create(const alicznik :Integer =0; const amianownik :Integer =1);
            procedure SetValues(const alicznik, amianownik :Integer);
            procedure GetValues(var rlicznik :Integer; var rmianownik :Integer); overload;
            procedure GetValues(plicznik, pmianownik :PInteger); overload;
            function ToFloat :Extended;
            function ToString :String;
        end;
    
    function IntToUlamek(const liczba :Integer) :Ulamek;
    function UlamekProd(const AUlamek1, AUlamek2 :Ulamek) :Ulamek;
    function UlamekQuot(const AUlamek1, AUlamek2 :Ulamek) :Ulamek;
    function UlamekSum(const AUlamek1, AUlamek2 :Ulamek) :Ulamek;
    function UlamekRevr(const AUlamek1 :Ulamek) :Ulamek;
    function UlamekDiff(const AUlamek1, AUlamek2 :Ulamek) :Ulamek;
    function UlamekCmp(const AUlamek1, AUlamek2 :Ulamek) :Integer;
    function UlamekToFloat(const AUlamek :Ulamek) :Extended;
    function UlamekToStr(const AUlamek :Ulamek) :String;
    
    implementation
    
    constructor Ulamek_Exception.Create(const AMessage :String);
    begin
    Message:=AMessage;
    end;
    
    function Ulamek_Exception.What :String;
    begin
    What:=Message;
    end;
    
    
    constructor Ulamek.Create(const alicznik :Integer =0; const amianownik :Integer =1);
    begin
    inherited Create; //TObject.Create()
    SetValues(alicznik,amianownik);
    end;
    
    procedure Ulamek.SetValues(const alicznik, amianownik :Integer);
    begin
    if amianownik=0 then raise Ulamek_Exception.Create('Ulamek: Blad #1');
    licznik:=alicznik;
    mianownik:=amianownik;
    end;
    
    procedure Ulamek.GetValues(var rlicznik :Integer; var rmianownik :Integer);
    begin
    rlicznik:=licznik;
    rmianownik:=mianownik;
    end;
    
    procedure Ulamek.GetValues(plicznik :PInteger; pmianownik :PInteger);
    begin
    plicznik^:=licznik;
    pmianownik^:=mianownik;
    end;
    
    function Ulamek.ToFloat :Extended;
    begin
    ToFloat:=licznik/mianownik;
    end;
    
    function Ulamek.ToString :String;
    begin
    ToString:=IntToStr(licznik)+'/'+IntToStr(mianownik);
    end;
    
    
    { FUNKCJA KONWERTUJACA }
    
    function IntToUlamek(const liczba :Integer) :Ulamek;
    begin
    IntToUlamek:=Ulamek.Create(liczba,1);
    end;
    
    function UlamekToFloat(const AUlamek :Ulamek) :Extended;
    begin
    UlamekToFloat:=AUlamek.ToFloat;
    end;
    
    function UlamekToStr(const AUlamek :Ulamek) :String;
    begin
    UlamekToStr:=AUlamek.ToString;
    end;
    
    
    {OPERACJE NA ULAMKACH }
    {iloczyn}
    function UlamekProd(const AUlamek1, AUlamek2 :Ulamek) :Ulamek;
    var alicznik1,amianownik1,alicznik2,amianownik2 :Integer;
    begin
    AUlamek1.GetValues(alicznik1,amianownik1);
    AUlamek2.GetValues(alicznik2,amianownik2);
    UlamekProd:=Ulamek.Create(alicznik1*alicznik2,amianownik1*amianownik2);
    end;
    
    {iloraz}
    function UlamekQuot(const AUlamek1, AUlamek2 :Ulamek) :Ulamek;
    var alicznik1,amianownik1,alicznik2,amianownik2 :Integer;
    begin
    AUlamek1.GetValues(alicznik1,amianownik1);
    AUlamek2.GetValues(alicznik2,amianownik2);
    UlamekQuot:=Ulamek.Create(alicznik1*amianownik2,amianownik1*alicznik2);
    end;
    
    {suma}
    function UlamekSum(const AUlamek1, AUlamek2 :Ulamek) :Ulamek;
    var alicznik1,amianownik1,alicznik2,amianownik2 :Integer;
    begin
    AUlamek1.GetValues(alicznik1,amianownik1);
    AUlamek2.GetValues(alicznik2,amianownik2);
    UlamekSum:=Ulamek.Create(alicznik1*amianownik2+alicznik2*amianownik1,amianownik1*amianownik2);
    end;
    
    {zmiana znaku}
    function UlamekRevr(const AUlamek1 :Ulamek) :Ulamek;
    var alicznik1,amianownik1 :Integer;
    begin
    AUlamek1.GetValues(alicznik1,amianownik1);
    UlamekRevr:=Ulamek.Create(-alicznik1,amianownik1);
    end;
    
    {roznica}
    function UlamekDiff(const AUlamek1, AUlamek2 :Ulamek) :Ulamek;
    var alicznik1,amianownik1,alicznik2,amianownik2 :Integer;
    begin
    AUlamek1.GetValues(alicznik1,amianownik1);
    AUlamek2.GetValues(alicznik2,amianownik2);
    UlamekDiff:=Ulamek.Create(alicznik1*amianownik2-alicznik2*amianownik1,amianownik1*amianownik2);
    end;
    
    {porownanie <, >, =}
    function UlamekCmp(const AUlamek1, AUlamek2 :Ulamek) :Integer;
    var alicznik1,amianownik1,alicznik2,amianownik2 :Integer;
        wynik :Double;
        int_wynik :Integer;
    begin
    AUlamek1.GetValues(alicznik1,amianownik1);
    AUlamek2.GetValues(alicznik2,amianownik2);
    wynik:=(alicznik1/amianownik1)-(alicznik1/amianownik2);
    if wynik=0 then int_wynik:=Round(wynik) else int_wynik:=Round(wynik/abs(wynik));
    UlamekCmp:=int_wynik;
    end;
    
    end.
    
    C#
    public class Ulamek
    {
    	private int licznik,mianownik;
    
    	public static readonly Ulamek Zero=new Ulamek(0,1);
    	public static readonly Ulamek Jeden=new Ulamek(1,1);
    	public static readonly Ulamek Polowa=new Ulamek(1,2);
    	public static readonly Ulamek Cwierc=new Ulamek(1,4);
    
    	public Ulamek(int alicznik,int amianownik)
    		{
    		set(alicznik,amianownik);
    		}
    
    	public Ulamek(Ulamek aulamek)
    		{
    		int olicznik,omianownik;
    		aulamek.get(out olicznik,out omianownik);
    		set(olicznik,omianownik);
    		}
    
    	public Ulamek Clone()
    		{
    		return new Ulamek(licznik,mianownik);
    		}
    
    	public void set(int alicznik,int amianownik)
    		{
    		if (amianownik==0) throw new Ulamek_Exception("Ulamek: Blad #1");
    		licznik=alicznik;
    		mianownik=amianownik;
    		}
    
    	public void get(out int rlicznik,out int rmianownik)
    		{
    		rlicznik=licznik;
    		rmianownik=mianownik;
    		}		
    
    	public void get(int[] arg)
    		{
    		arg[0]=licznik;
    		arg[1]=mianownik;
    		}
    
    	public int[] get()
    		{
    		int[] wynik=new int[2];
    		wynik[0]=licznik;
    		wynik[1]=mianownik;
    		return wynik;
    		}
    
    	public override string ToString()
    		{
    		return ""+licznik+"/"+mianownik;
    		}
    
    	public double ToDouble()
    		{
    		return licznik/(double)mianownik;
    		}
    
    	//konwersja z Ulamek na double
    	public static implicit operator double(Ulamek aulamek)
    		{
    		return aulamek.ToDouble();
    		}
    
    	//konwersja z int na Ulamek
    	public static implicit operator Ulamek(int aliczba_calkowita)
    		{
    		return new Ulamek(aliczba_calkowita,1);
    		}
    }
    
    Przykład kodu
    ShowMessage((double)ulamek(1,2));
    ShowMessage((double)ulamek(1,3));
    
    ShowMessage((char*)ulamek(1,2));
    ShowMessage((char*)ulamek(1,3));
    
    Przykład kodu:
      Ulamek a=null,b=null;
      try
        {
        a=new Ulamek(1,2);
        b=new Ulamek(1,3);
        }
      catch(Exception E)
        {
        list1.add(E.getMessage());
        }
    
      list1.add("a: "+String.valueOf(a.toDouble()));
      list1.add("b: "+String.valueOf(b.toDouble()));
    
      list1.add("a: "+a.toString()); //jawna konwersja na String
      list1.add("b: "+b.toString());
    
      list1.add("a: "+String.valueOf(a)); //jawna konwersja na String
      list1.add("b: "+String.valueOf(b)); //korzysta z toString
    
      list1.add("a: "+a); //niejawna konwersja na String
      list1.add("b: "+b); //korzysta z toString
    
    Pascal
    procedure TForm1.Button1Click(Sender: TObject);
    var a,b :Ulamek;
    begin
    a:=Ulamek.Create(1,2);
    b:=Ulamek.Create(1,3);
    
    ShowMessage('a: '+FloatToStr(a.ToFloat)+', b: '+FloatToStr(b.ToFloat));
    ShowMessage('a: '+a.ToString+', b: '+b.ToString);
    
    ShowMessage('a: '+FloatToStr(UlamekToFloat(a))+', b: '+FloatToStr(UlamekToFloat(b)));
    ShowMessage('a: '+UlamekToStr(a)+', b: '+UlamekToStr(b));
    end;
    
    Przykład kodu:
    MessageBox.Show(Ulamek.Polowa.ToString());
    MessageBox.Show(""+Ulamek.Polowa);
    
    MessageBox.Show(""+Ulamek.Polowa.ToDouble());
    MessageBox.Show(""+(1.0+Ulamek.Polowa)); //niejawna konwersja na double
    
    Ulamek a=2;
    MessageBox.Show(""+a);
    

    Uwaga!


    Metoda "uproszczenie ułamka":

    Elegancja klasy wymaga metody porządkującej i upraszczającej licznik i mianownik. Znak minus powinien znajdować się tylko przy liczniku, licznik i mianownik powinny mieć najmniejszą możliwą wartość (należy znaleźć NWD).
    Do szukania NWD istnieje wiele wyrafinowanych algorytmów, tutaj zadowolę się najprostszym jaki przyszedł mi do głowy.

    C++
    void simplify()
        {
        //NWD
        int mniejsza=(abs(licznik)<abs(mianownik))
    	             ?abs(licznik):abs(mianownik);
        for(int i=mniejsza;i>0;i--)
            if ((licznik%i==0) && (mianownik%i==0))
                {
                licznik/=i;
                mianownik/=i;
                }
         //znaki
         if (licznik*mianownik<0)
             {
             licznik=-abs(licznik);
             mianownik=abs(mianownik);
             }
             else
             {
             licznik=abs(licznik);
             mianownik=abs(mianownik);
             }
        }
    
    Java
    public void simplify()
      {
      //NWD
      int mniejsza=(Math.abs(licznik)<Math.abs(mianownik))
                   ?Math.abs(licznik):Math.abs(mianownik);
      for(int i=mniejsza;i>0;i--)
          if ((licznik%i==0) && (mianownik%i==0))
              {
              licznik/=i;
              mianownik/=i;
              }
       //znaki
       if (licznik*mianownik<0)
           {
           licznik=-Math.abs(licznik);
           mianownik=Math.abs(mianownik);
           }
           else
           {
           licznik=Math.abs(licznik);
           mianownik=Math.abs(mianownik);
           }
        }
    
    
    Pascal
    procedure Ulamek.Simplify;
    var mniejsza,i :Integer;
    begin
    //NWD
    mniejsza:=Min(abs(licznik),abs(mianownik));
    
    for i:=mniejsza downto 1 do
        if (licznik mod i=0) and (mianownik mod i=0) then
            begin
            licznik:=licznik div i;
            mianownik:=mianownik div i;
            end;
    
    //znaki
    if licznik*mianownik<0 then
        begin
        licznik:=-abs(licznik);
        mianownik:=abs(mianownik);
        end
        else
        begin
        licznik:=abs(licznik);
        mianownik:=abs(mianownik);
        end;
    end;
    
    C#
    public void simplify()
    	{
    	//NWD
    	int mniejsza=(Math.Abs(licznik)0;i--)
    		if ((licznik%i==0) && (mianownik%i==0))
    			{
    			licznik/=i;
    			mianownik/=i;
    			}
    	
    	//znaki
    	if (licznik*mianownik<0)
    		{
    		licznik=-Math.Abs(licznik);
    		mianownik=Math.Abs(mianownik);
    		}
    		else
    		{
    		licznik=Math.Abs(licznik);
    		mianownik=Math.Abs(mianownik);
    		}
    	}
    
    Przykład kodu
    ulamek a(30,-75);
    
    int licznik,mianownik;
    a.get(licznik,mianownik);
    ShowMessage((AnsiString)"nieuproszczone a: "+licznik+"/"+mianownik);
    
    a.simplify();
    
    a.get(licznik,mianownik);
    ShowMessage((AnsiString)"uproszczone a: "+licznik+"/"+mianownik);
    
    Przykład kodu
    Ulamek a=null,b=null;
    try
      {
      a=new Ulamek(30,-75);
      }
    catch(Exception E)
      {
      list1.add(E.getMessage());
      }
    
    list1.add("a: "+a);
    a.simplify();
    
    list1.add("b: "+a);
    
    Pascal
    procedure TForm1.Button1Click(Sender: TObject);
    var a :Ulamek;
    begin
    a:=Ulamek.Create(30,-75);
    
    ShowMessage('nieuproszczone a: '+a.ToString());
    
    a.Simplify();
    
    ShowMessage('uproszczone a: '+a.ToString());
    end;
    
    Przykład kodu
    Ulamek a=new Ulamek(128,-96);
    a.simplify();
    MessageBox.Show(""+a);
    

    Uwaga!
    Mozna uczynić simplify() metodą prywatna, a za to wywolywac ja przy kazdym get(). Tutaj możliwość wykorzystania tej metody pozostawiona została użytkownikowi klasy.


    Rozdzielenie deklaracji i definicji klasy, pliki nagłówkowy i źródłowy:

    C++: W C++ zazwyczaj klasy umieszcza się w dwóch oddzielnych plikach tak, żeby rozdzielić deklarację umieszczoną w pliku nagłówkowym (ang. header file) od definicji znajdującej się w pliku źródłowym (ang. source file). Metody, których definicja pozostawiona zostanie w pliku nagłówkowym w obrębie deklaracji pozostają metodami inline. Metody przeniesione do pliku źródłowego przestają być inline, chyba, że użyte zostanie słowo kluczowe inline w ich definicji. Rozdzielenie plików deklaracji i definicji jest dobrym zwyczajem C++ pozwalającym między innymi na uproszczoną dystrybucję klas/bibliotek klas.

    Delphi: W Delphi wewnątrz modułu rozdzielenie deklaracji i definicji jest obowiązkowe ze względu na gramatykę Pascala.

    Java: W Javie definicja metod musi znajdować się w obrębie deklaracji klasy. Nie oznacza to wcale, że są metodami inline.

    C++

    Plik nagłówkowy (ulamek.h):

    const ulamek_maxstr=1024;
    
    class ulamek
        {
        private:
        	int licznik, mianownik;
            double to_double() const;
            char* to_string() const;
            AnsiString to_AnsiString() const;
        public:
        	ulamek(int alicznik=0,int amianownik=1)
                {
                set(alicznik,amianownik);
                }
        	ulamek(const ulamek& aulamek)
                {
                aulamek.get(licznik,mianownik);
                }
        	void set(int alicznik,int amianownik);
            void simplify();
            void get(int& rlicznik,int& rmianownik) const;
            void get(int* plicznik,int* pmianownik) const;
            operator double() const {return to_double();}
            operator char*() const {return to_string();}
        };
    
    const ulamek ulamek_zero(0,1);
    const ulamek ulamek_jeden(1,1);
    const ulamek ulamek_polowa(1,2);
    const ulamek ulamek_cwierc(1,4);
    

    Plik źródłowy (ulamek.cpp):

    #include "ulamek.h"
    
    inline double ulamek::to_double() const
        {
        return licznik/(double)mianownik;
        }
    char* ulamek::to_string() const
        {
        char str_licznik[ulamek_maxstr]; itoa(licznik,str_licznik,10);
        char str_mianownik[ulamek_maxstr]; itoa(mianownik,str_mianownik,10);
        char* str=str_licznik;
        strcat(str,"/");
        strcat(str,str_mianownik);
        return str;
        }
    void ulamek::set(int alicznik,int amianownik)
        {
        if (amianownik==0) throw "Ulamek: Blad #1";
        licznik=alicznik;
        mianownik=amianownik;
        }
    void ulamek::simplify()
        {
        //NWD
        int mniejsza=(licznik<mianownik)?licznik:mianownik;
        for(int i=mniejsza;i>0;i--)
            if ((licznik%i==0) && (mianownik%i==0))
                    {
                    licznik/=i;
                    mianownik/=i;
                    }
                //znaki
            if (licznik*mianownik<0)
                    {
                    licznik=-abs(licznik);
                    mianownik=abs(mianownik);
                    }
                    else
                    {
                    licznik=abs(licznik);
                    mianownik=abs(mianownik);
                    }
             }
    inline void ulamek::get(int& rlicznik,int& rmianownik) const
        {
        rlicznik=licznik;
        rmianownik=mianownik;
        }
    inline void ulamek::get(int* plicznik,int* pmianownik) const
        {
        *plicznik=licznik;
        *pmianownik=mianownik;
        }
    
    
    ulamek operator *(const ulamek& aulamek1,const ulamek& aulamek2)
        {
        int alicznik1=0,amianownik1=1;aulamek1.get(alicznik1,amianownik1);
        int alicznik2=0,amianownik2=1;aulamek2.get(alicznik2,amianownik2);
        return ulamek(alicznik1*alicznik2,amianownik1*amianownik2);
        };
    ulamek operator /(const ulamek& aulamek1,const ulamek& aulamek2)
        {
        int alicznik1=0,amianownik1=1;aulamek1.get(alicznik1,amianownik1);
        int alicznik2=0,amianownik2=1;aulamek2.get(alicznik2,amianownik2);
        return ulamek(alicznik1*amianownik2,amianownik1*alicznik2);
        };
    ulamek operator +(const ulamek& aulamek1,const ulamek& aulamek2)
        {
        int alicznik1=0,amianownik1=1;aulamek1.get(alicznik1,amianownik1);
        int alicznik2=0,amianownik2=1;aulamek2.get(alicznik2,amianownik2);
        return ulamek(alicznik1*amianownik2+alicznik2*amianownik1,amianownik1*amianownik2);
        };
    ulamek operator -(const ulamek& aulamek1)
        {
        int alicznik1=0,amianownik1=1;aulamek1.get(alicznik1,amianownik1);
        return ulamek(-alicznik1,amianownik1);
        };
    ulamek operator -(const ulamek& aulamek1,const ulamek& aulamek2)
        {
        int alicznik1=0,amianownik1=1;aulamek1.get(alicznik1,amianownik1);
        int alicznik2=0,amianownik2=1;aulamek2.get(alicznik2,amianownik2);
        return ulamek(alicznik1*amianownik2-alicznik2*amianownik1,amianownik1*amianownik2);
        };
    bool operator <(const ulamek& aulamek1,const ulamek& aulamek2)
        {
        int alicznik1=0,amianownik1=1;aulamek1.get(alicznik1,amianownik1);
        int alicznik2=0,amianownik2=1;aulamek2.get(alicznik2,amianownik2);
        return (alicznik1/(double)amianownik1)<(alicznik2/(double)amianownik2);
        };
    bool operator >(const ulamek& aulamek1,const ulamek& aulamek2)
        {
        int alicznik1=0,amianownik1=1;aulamek1.get(alicznik1,amianownik1);
        int alicznik2=0,amianownik2=1;aulamek2.get(alicznik2,amianownik2);
        return (alicznik1/(double)amianownik1)>(alicznik2/(double)amianownik2);
        };
    bool operator ==(const ulamek& aulamek1,const ulamek& aulamek2)
        {
        int alicznik1=0,amianownik1=1;aulamek1.get(alicznik1,amianownik1);
        int alicznik2=0,amianownik2=1;aulamek2.get(alicznik2,amianownik2);
        return (alicznik1/(double)amianownik1)==(alicznik2/(double)amianownik2);
        };
    
    Przykład kodu
     
    //TABLICE ULAMKOW
    //ShowMessage("Zakres liczb pseudolosowych: "+(AnsiString)(double)RAND_MAX); 
    const zakres=100; 
    const ilosc=10; 
    ulamek a[ilosc]; 
    randomize(); 
    for(int i=0;i<ilosc;i++)
        {
        ulamek b=ulamek(rand() % zakres,rand() % zakres);
        a[i]=b;
        a[i].simplify();
        ShowMessage((AnsiString)(char*)b+" = "+(char*)a[i]);
        }
    	
    //TYPOWE ZASTOSOWANIA
    ShowMessage((double)ulamek_polowa+0.1);
    ShowMessage(1/2);
    ulamek c=3/4;
    ShowMessage((char*)c);
    c=(ulamek)3/(ulamek)4;
    ShowMessage((char*)c);
    
    

    Uwaga!
    C++: Używanie metod inline w przypadku bardziej złożonych funkcji nie jest zalecane - utrudnia to kompilatorowi optymalizację kodu wynikowego.


    Szablon klasy:

    Przygotujemy szablon (tylko C++):
    1. Przed deklaracją klasy dodajemy: template <class T>
    2. T powinno zastąpić wszystkie użycia int w obrębie deklaracji.
    3. W definicji przed każdą metodą nalezy użyć template <class T> oraz przy każdym ułamek dodać specyfikację typu <T> (tzn. ulamek<T>).
    C++

    Plik nagłówkowy (ulamek.h):

    #include 
    
    const ulamek_maxstr=1024;
    
    template <class T>
    class ulamek
        {
        private:
        	T licznik, mianownik;
            double to_double() const;
            char* to_string() const;
        public:
        	ulamek(T alicznik=0,T amianownik=1)
                {
                //Szablon obsluguje tylko typy calkowite
    			if (!(
                	typeid(T)==typeid(unsigned char) ||
                    typeid(T)==typeid(char) ||
                    typeid(T)==typeid(short int) ||
                    typeid(T)==typeid(unsigned int) ||
                    typeid(T)==typeid(int) ||
                    typeid(T)==typeid(unsigned long) ||
                    typeid(T)==typeid(long)
                   )) throw "Ulamek: Blad #2";
    
                set(alicznik,amianownik);
                }
        	ulamek(const ulamek& aulamek)
                {
                aulamek.get(licznik,mianownik);
                }
        	void set(T alicznik,T amianownik);
            void simplify();
            void get(T& rlicznik,T& rmianownik) const;
            void get(T* plicznik,T* pmianownik) const;
            operator double() const {return to_double();}
            operator char*() const {return to_string();}
        };
    
    /*
    //Szablony muszą być klasami lub funkcjami
    const ulamek ulamek_zero(0,1);
    const ulamek ulamek_jeden(1,1);
    const ulamek ulamek_polowa(1,2);
    const ulamek ulamek_cwierc(1,4);
    */
    

    Plik główny (ulamek.cpp):

    #include "ulamek.h"
    
    template <class T> inline double ulamek<T>::to_double() const
        {
        return licznik/(double)mianownik;
        }
    template <class T> char* ulamek<T>::to_string() const
        {
        char str_licznik[ulamek_maxstr]; itoa(licznik,str_licznik,10);
        char str_mianownik[ulamek_maxstr]; itoa(mianownik,str_mianownik,10);
        char* str=str_licznik;
        strcat(str,"/");
        strcat(str,str_mianownik);
        return str;
        }
    template <class T> void ulamek<T>::set(T alicznik,T amianownik)
        {
        if (amianownik==0) throw "Ulamek: Blad #1";
        licznik=alicznik;
        mianownik=amianownik;
        }
    template <class T> void ulamek<T>::simplify()
        {
        //NWD
        T mniejsza=(abs(licznik)<abs(mianownik))?abs(licznik):abs(mianownik);
        for(T i=mniejsza;i>0;i--)
            if ((licznik%i==0) && (mianownik%i==0))
                    {
                    licznik/=i;
                    mianownik/=i;
                    }
                //znaki
            if (licznik*mianownik<0)
                    {
                    licznik=-abs(licznik);
                    mianownik=abs(mianownik);
                    }
                    else
                    {
                    licznik=abs(licznik);
                    mianownik=abs(mianownik);
                    }
             }
    template <class T> inline void ulamek<T>::get(T& rlicznik,T& rmianownik) const
        {
        rlicznik=licznik;
        rmianownik=mianownik;
        }
    template <class T> inline void ulamek<T>::get(T* plicznik,T* pmianownik) const
        {
        *plicznik=licznik;
        *pmianownik=mianownik;
        }
    
    
    template <class T> ulamek<T> operator *(const ulamek<T>& aulamek1,const ulamek<T>& aulamek2)
        {
        T alicznik1=0,amianownik1=1;aulamek1.get(alicznik1,amianownik1);
        T alicznik2=0,amianownik2=1;aulamek2.get(alicznik2,amianownik2);
        return ulamek<T>(alicznik1*alicznik2,amianownik1*amianownik2);
        };
    template <class T> ulamek<T> operator /(const ulamek<T>& aulamek1,const ulamek<T>& aulamek2)
        {
        T alicznik1=0,amianownik1=1;aulamek1.get(alicznik1,amianownik1);
        T alicznik2=0,amianownik2=1;aulamek2.get(alicznik2,amianownik2);
        return ulamek<T>(alicznik1*amianownik2,amianownik1*alicznik2);
        };
    template <class T> ulamek<T> operator +(const ulamek<T>& aulamek1,const ulamek<T>& aulamek2)
        {
        T alicznik1=0,amianownik1=1;aulamek1.get(alicznik1,amianownik1);
        T alicznik2=0,amianownik2=1;aulamek2.get(alicznik2,amianownik2);
        return ulamek<T>(alicznik1*amianownik2+alicznik2*amianownik1,amianownik1*amianownik2);
        };
    template <class T> ulamek<T> operator -(const ulamek<T>& aulamek1)
        {
        T alicznik1=0,amianownik1=1;aulamek1.get(alicznik1,amianownik1);
        return ulamek<T>(-alicznik1,amianownik1);
        };
    template <class T> ulamek<T> operator -(const ulamek<T>& aulamek1,const ulamek<T>& aulamek2)
        {
        T alicznik1=0,amianownik1=1;aulamek1.get(alicznik1,amianownik1);
        T alicznik2=0,amianownik2=1;aulamek2.get(alicznik2,amianownik2);
        return ulamek<T>(alicznik1*amianownik2-alicznik2*amianownik1,amianownik1*amianownik2);
        };
    template <class T> bool operator <(const ulamek<T>& aulamek1,const ulamek<T>& aulamek2)
        {
        T alicznik1=0,amianownik1=1;aulamek1.get(alicznik1,amianownik1);
        T alicznik2=0,amianownik2=1;aulamek2.get(alicznik2,amianownik2);
        return (alicznik1/(double)amianownik1)<(alicznik2/(double)amianownik2);
        };
    template <class T> bool operator >(const ulamek<T>& aulamek1,const ulamek<T>& aulamek2)
        {
        T alicznik1=0,amianownik1=1;aulamek1.get(alicznik1,amianownik1);
        T alicznik2=0,amianownik2=1;aulamek2.get(alicznik2,amianownik2);
        return (alicznik1/(double)amianownik1)>(alicznik2/(double)amianownik2);
        };
    template <class T> bool operator ==(const ulamek<T>& aulamek1,const ulamek<T>& aulamek2)
        {
        int alicznik1=0,amianownik1=1;aulamek1.get(alicznik1,amianownik1);
        int alicznik2=0,amianownik2=1;aulamek2.get(alicznik2,amianownik2);
        return (alicznik1/(double)amianownik1)==(alicznik2/(double)amianownik2);
        };
    
    Przykład kodu
     
    typedef ulamek<long> long_ulamek;
    
    const long_ulamek long_ulamek_zero(0,1);
    const long_ulamek long_ulamek_jeden(1,1);
    const long_ulamek long_ulamek_polowa(1,2);
    const long_ulamek long_ulamek_cwierc(1,4);
    
    const zakres=100;
    const ilosc=10;
    try
        {
        long_ulamek a[ilosc];
        randomize();
        for(int i=0;i<ilosc;i++)
        	{
            long_ulamek b=long_ulamek(rand() % zakres,rand() % zakres);
        	a[i]=b;
        	a[i].simplify();
        	ShowMessage((AnsiString)(char*)b+" = "+(char*)a[i]);
        	}
        }
    catch(char* E)
        {
        ShowMessage(E);
        exit(EXIT_FAILURE);
        }
    

    Uwaga!


    Dziedziczenie publiczne:

    Dziedziczenie/rozszerzanie klas jest sposobem na uwspólnianie części kodu, hermetyzację implementacji oraz wykorzystanie innych zalet dziedziczenia (np. poliformizmu). Jest również dobrym zwyczajem umieszczanie w klasie bazowej silnika działania klasy, a w klasie potomnej interface'u. Pomaga to uchronić się od błędu i od dostosowywania implementacji do potrzeb drugorzędnych.
    Aby dziedziczyć z klasy ulamek, musimy jej implementację umieszczoną w części prywatnej "awansować" do sekcji chronionej. W praktyce oznacza to zamianę słowa kluczowego private na protected.
    W przypadku operatorów zdefiniowanych poza klasą pojawi się problem: wartość zwracana przez te operatory jest obiektem klasy bazowej, a nie potomnej. Operatory powinny być powtórzone dla nowej klasy. Można w takim przypadku skorzystać z operatorów dla klasy bazowej, ale należy do klasy dodać funkcję pozwalającą na konwersję klasy bazowej na potomną (konwersja odwrotna jest automatyczna).

    C++
    template <class T>
    class ansistring_ulamek : public ulamek<T>
        {
        private:
            AnsiString to_AnsiString() const
                {
                return (AnsiString)licznik+'/'+(AnsiString)mianownik;
                }
        public:
        	ansistring_ulamek(T alicznik=0,T amianownik=1):ulamek<T>(alicznik,amianownik)
                {
                }
            from_ulamek(ulamek<T> aulamek)
                {
                aulamek.get(licznik,mianownik);
                }
            operator AnsiString()
                {
                return to_AnsiString();
                }
        };
    
    
    //operatory zwracajace obiekt klasy potomnej
    template <class T> ansistring_ulamek<T> operator *(const ansistring_ulamek<T>& aulamek1,
                                                       const ansistring_ulamek<T>& aulamek2)
        {
        ansistring_ulamek<T> as_ulamek;
        as_ulamek.from_ulamek((ulamek<T>)aulamek1*(ulamek<T>)aulamek2);
        return as_ulamek;
        };
    template <class T> ansistring_ulamek<T> operator /(const ansistring_ulamek<T>& aulamek1,
                                                       const ansistring_ulamek<T>& aulamek2)
        {
        ansistring_ulamek<T> as_ulamek;
        as_ulamek.from_ulamek((ulamek<T>)aulamek1/(ulamek<T>)aulamek2);
        return as_ulamek;
        };
    template <class T> ansistring_ulamek<T> operator +(const ansistring_ulamek<T>& aulamek1,
                                                       const ansistring_ulamek<T>& aulamek2)
        {
        ansistring_ulamek<T> as_ulamek;
        as_ulamek.from_ulamek((ulamek<T>)aulamek1+(ulamek<T>)aulamek2);
        return as_ulamek;
        };
    template <class T> ansistring_ulamek<T> operator -(const ansistring_ulamek<T>& aulamek1)
        {
        ansistring_ulamek<T> as_ulamek;
        as_ulamek.from_ulamek(-(ulamek<T>)aulamek1);
        return as_ulamek;
        };
    template <class T> ansistring_ulamek<T> operator -(const ansistring_ulamek<T>& aulamek1,
                                                       const ansistring_ulamek<T>& aulamek2)
        {
        ansistring_ulamek<T> as_ulamek;
        as_ulamek.from_ulamek((ulamek<T>)aulamek1-(ulamek<T>)aulamek2);
        return as_ulamek;
        };
    
    Java (plik CString_Ulamek.java)
    package klasy;
    
    public class CString_Ulamek extends Ulamek implements Cloneable
    {
      public CString_Ulamek(int alicznik,int amianownik)
        throws Exception
        {
        super(alicznik,amianownik);
        }
    
      public char[] toCString()
        {
        String swynik=this.toString();
        char[] cwynik = new char[swynik.length()];
        swynik.getChars(0, swynik.length(), cwynik, 0);
        return cwynik;
        }
    }
    
    Pascal
    unit _cstring_ulamek;
    
    interface
    
    uses _ulamek, SysUtils;
    type
    CString = array of Char; //tablica dynamiczna
    PCString = ^CString;
    
    CString_Ulamek = class(Ulamek)
        public
            constructor Create(const alicznik :Integer =0; const amianownik :Integer =1);
            procedure ToCString(const buffer_pointer :PCString;var buffer_length :Integer);
            procedure ToPChar(const buffer_pointer :PChar;const buffer_length :Integer);
        end;
    
    
    implementation
    
    constructor CString_Ulamek.Create(const alicznik :Integer =0; const amianownik :Integer =1);
    begin
    inherited; //Ulamek.Create(licznik,mianownik)
    end;
    
    procedure CString_Ulamek.ToCString(const buffer_pointer :PCString;var buffer_length :Integer);
    var s :String;
        i :Integer;
    begin
    s:=IntToStr(licznik)+'/'+IntToStr(mianownik);
    buffer_length:=Length(s);
    SetLength(buffer_pointer^,buffer_length);
    for i:=0 to buffer_length-1 do buffer_pointer^[i]:=s[i+1]; //s numerowane od 1
    end;
    
    procedure CString_Ulamek.ToPChar(const buffer_pointer :PChar;const buffer_length :Integer);
    var s :String;
        i :Integer;
    begin
    s:=IntToStr(licznik)+'/'+IntToStr(mianownik);
    StrPLCopy(buffer_pointer,s,buffer_length);
    end;
    
    
    {Tu powinny byc operatory dla CString_Ulamek}
    
    end.
    
    C#
    public class CString_Ulamek : Ulamek
    {
    	public CString_Ulamek(int alicznik,int amianownik):base(alicznik,amianownik)
    		{
    		}
    
    	public char[] ToCString()
    		{
    		return this.ToString().ToCharArray();
    		}
    
    	public static explicit operator char[](CString_Ulamek acstring_ulamek)
    		{
    		return acstring_ulamek.ToCString();
    		}
    }
    
    Przykład kodu
     
    ulamek a=ulamek(1,2);
    ShowMessage((char*)a);
    
    ansistring_ulamek b=ansistring_ulamek(3,4);
    ShowMessage(b);
    
    ansistring_ulamek d1=3, d2=4;
    ShowMessage(d1+d2);
    ShowMessage(-d1);
    ShowMessage(d1-d2);
    ShowMessage(d1*d2);
    ShowMessage(d1/d2);
    
    Przykład kodu
    CString_Ulamek a=null;
    try{a=new CString_Ulamek(30,-75);}catch(Exception E){list1.add(E.getMessage());}
    a.simplify();
    char[] c=a.toCString();
    list1.add("a: "+String.valueOf(c));
    
    Pascal
    procedure TForm1.Button1Click(Sender: TObject);
    var a :CString_Ulamek;
        buffer :CString;
        buffer1 :array of Char;
        buffer_size :Integer;
        s :String;
    begin
    a:=CString_Ulamek.Create(1,2);
    
    a.ToCString(@buffer,buffer_size);
    ShowMessage('dlugosc bufora: '+IntToStr(buffer_size));
    ShowMessage('zawartosc bufora: '+String(buffer));
    
    a.ToCString(@s,buffer_size);
    ShowMessage('dlugosc bufora: '+IntToStr(buffer_size));
    ShowMessage('zawartosc bufora: '+s);
    
    a.ToPChar(PChar(buffer),Length(buffer));
    ShowMessage('dlugosc bufora: '+IntToStr(Length(buffer)));
    ShowMessage('zawartosc bufora: '+String(buffer));
    end;
    
    Przykład kodu
    CString_Ulamek a=new CString_Ulamek(1,2);
    char[] ac=a.ToCString();
    MessageBox.Show(""+ac[1]);
    MessageBox.Show(""+((char[])a)[1]);
    

    Uwaga!


    Nieomówione zagadnienia dotyczące klas:

    (c) Jacek Matulewski 2003-2004 (jacek@phys.uni.torun.pl)
    wersja z dnia: 22 VIII 2004