Programowanie w języku Delphi

Rekordy

  • 2006-01-19 12:13
  • 3 komentarze
  • 7258 odsłon
  • Oceń ten tekst jako pierwszy
Rekordy są zorganizowaną strukturą danych, połączona w jedną całość. Jest to jakby zestaw zawierający określone elementy.



Rekordy również można przekazywać ? jako zestaw elementów ? do funkcji czy procedur w formie parametru.

Nowe rekordy można deklarować jako nowy typ danych lub jako zmienną przy użyciu słowa kluczowego record.

type
  TMyRecord = record
    X : Integer;
    Y : Integer;
  end;


Budowa deklaracji rekordu, jak widać, jest specyficzna ? najpierw należy wpisać jego nazwę, a potem po znaku równości słowo kluczowe record (uwaga, brak średnika na końcu!). Następnie wypisujemy elementy, z których ma się składać nasz rekord.

Jako że powyżej zadeklarowaliśmy rekord jako nowy typ danych, należy utworzyć dodatkowo zmienną wskazującą na ten typ. Przy tej okazji przedstawię nowy operator Delphi ? kropkę (.). Do poszczególnych pól rekordu odwołujemy się następująco:

MyRecord.X := 1;


po uprzednim utworzeniu zmiennej wskazującej na rekord.

Po co stosować rekordy? Czasem trzeba przekazać określoną strukturę jako parametr funkcji bądź procedury. Można by oczywiście przekazywać pojedynczo kolejne elementy do procedury, jednak często wygodniej przekazać jeden parametr ? w formie rekordu. Usprawnia to pracę i jest dość często stosowanym elementem programów.

Rekordy jako parametry funkcji i procedur


Napiszmy prosty program, który pobierze dwie liczby wpisane przez użytkownika i przekaże do procedury cały rekord.
Samo przekazanie rekordu do funkcji przebiega w sposób dość prosty:

type
  TMyRecord = record
    X : Integer;
    Y : Integer;
  end;
 
  function Dzielenie(MyRecord : TMyRecord) : Integer;
  begin
    Result := MyRecord.X div MyRecord.Y;
  end;


Delphi wymaga, aby do funkcji Dzielenie został przekazany rekord TMyRecord. Kolejno następuje podzielenie elementu X przez element Y rekordu i zwrócenie wartości dzielenia. Cały program wygląda tak jak na listingu poniżej.

program Recordapp;
 
{$APPTYPE CONSOLE}
 
type
  TMyRecord = record
    X : Integer;
    Y : Integer;
  end;
 
  function Dzielenie(MyRecord : TMyRecord) : Integer;
  begin
    Result := MyRecord.X div MyRecord.Y;
  end;
 
var
  MyRecord : TMyRecord;
  Result : Integer;
 
begin
  Writeln('Podaj pierwszą liczbę');
  Readln(MyRecord.X);
 
  Writeln('Podaj drugą liczbę');
  Readln(MyRecord.Y);
 
  Result := Dzielenie(MyRecord);
 
  Writeln('Rezultat dzielenia');
  Writeln(Result);
  Readln;
end.


Na samym początku tego programu zadeklarowano nowy typ ? TMyRecord, który jest rekordem. Teraz, żeby takiego rekordu użyć, należy zadeklarować zmienną, która wskazuje na ten typ.

Dalsza część programu powinna być oczywista ? pobieramy tutaj dwie wartości od użytkownika i przypisujemy je do elementów rekordów, tak jak robimy to ze zwykłą zmienną. Następnie cały rekord przekazujemy do funkcji, która dokonuje dzielenia.

Deklarowanie rekordu jako zmiennej


Nie jest konieczne tworzenie nowego typu dla rekordu. Oznacza to, że zamiast deklarować kolejny rekord jako nowy typ (type), można zadeklarować go jako zmienną:

var
  Rec : record
    X, Y : Integer;
  end;


Wówczas nie jest też konieczne tworzenie nowej zmiennej ? od razu można zabrać się za przypisywanie danych do elementów rekordu.

Metody w rekordach


Delphi 8 wprowadza pewne innowacje w zapisie rekordów. Dotychczas rekord mógł zawierać jedynie pola (ang. fields), czyli zmienne rekordowe. Teraz jest możliwe także dodawanie metod, co bardziej upodobnia rekordy do klas. Oczywiście, rekordy są prostszą strukturą niż klasy i nie mogą zwierać metod wirtualnych czy dynamicznych. Nie można dziedziczyć rekordów oraz przedefiniowywać metod.

Metody w rekordach deklaruje się identycznie jak w klasach:

type
  TRecord = record
    X, Y : Integer;
    procedure Main;
  end;


Należy zwrócić uwagę, że jawne wywołanie konstruktora w rekordzie nie jest możliwe. Oczywiście, istnieje możliwość jego deklaracji, ale jego wywołanie następuje automatycznie w momencie skorzystania z metody w rekordzie.

Deklaracja konstruktora musi nastąpić z użyciem słowa kluczowego class, tak jak poniżej:

type
  TRecord = record
    X, Y : Integer;
    procedure Main;
    class constructor Create;
  end;


W razie zaniechania użycia słowa kluczowego class, Delphi wyświetli komunikat o błędzie: [Error] Uni1.pas(110): Parameterless constructors not allowed on record types.

Należy również pamiętać o specyficznej budowie nagłówka metody, tak jak w przypadku klas, czyli:
procedure/function Klasa.Nazwa [parametry]

Spójrzmy na poniższy fragment kodu:

procedure TWinForm2.Button1_Click(sender: System.Object; e: System.EventArgs);
var
  R : TRecord;
begin
  R.X := 57; // przydzielenie wartości
  R.Main; // wywołanie metody
end;
 
 
{ TRecord }
 
class constructor TRecord.Create;
begin
  MessageBox.Show('Rozpoczynam używanie rekordu TRecord...');
end;
 
procedure TRecord.Main;
begin
  MessageBox.Show('Mój wiek: ' + Convert.ToString(X));
end;


Powyższy przykład jest oczywiście niezbyt praktyczny i użyteczny, ale pozwala na zaprezentowanie działania rekordów i wywoływania konstruktora. Można wkleić taki kod do swojego programu i zaobserwować jego działanie.

Po naciśnięciu przycisku najpierw w okienku informacyjnym pojawi się tekst: Rozpoczynam używanie rekordu TRecord..., a dopiero później: Mój wiek: 57.

W rekordach nie można używać destruktora. Przy próbie jego wykorzystania Delphi wyświetli komunikat o błędzie: [Error] Uni1.pas(111): PROCEDURE, FUNCTION, PROPERTY, or VAR expected lub [Error] Uni1.pas(111): Unsupported language feature: 'destructor'.

Metody deklarowane w rekordach są domeną języka Delphi dla .NET ? kompilator Delphi dla Win32 nie dopuści do kompilacji takiego kodu.



Zobacz też:

3 komentarze

Brak avatara
nemo 2014-01-03 11:43

Czy jest możliwy odczyt liczby pól rekordu? W sensie

type
  TRec = record
    X : Integer;
    Y : Integer;
  end;
...
var
 Zmienna: TRec;
...
JakiesDzialanie(Zmienna) wynik 2 (bo są dwa pola)? Oczywiście z poziomu delphi a nie delphi+assembler czy delphi+przeszukiwanie pamięci.

Pewnym rozwiązaniem jest SizeOf(zmienna) (lub SizeOf(TRec )), ale sprawdza się ono przy jednorodnych (tzn. wszystkie tego samego typu) rekordach, wtedy LiczbaPol = SizeOf(Zmienna) div RozmiarPojedynczegoRekordu
RozmiarPojedynczegoRekordu = 16 (extended), 4 (integer), 1 (byte), etc.

I powiązane pytanie: czy jest możliwy (znów czysty delphi, bez assemblera czy gmerania w pamięci) dostęp do pól rekordu BEZ odwoływania się do ich nazwy? Czyli jak w powyższym przykładzie zamiast

Zmienna.X

coś w stylu zmienna.[0]? Pomijam oczywiście zbudowanie rekordu w postaci tablicy (czyli zamiast
type
  TRec = record
    X : Integer;
    Y : Integer;
  end;

zrobić:
type
  TRec = array [0..1] of integer;
)

Brak avatara
... 2013-10-28 10:02

program podobno ma być w delphi a jest w języku pascal

adydan 2009-07-22 12:24

Nie będę się wcinał w dzieło mistrza dorzucę to tylko w komentarzu.

Istnieje możliwość deklarowania tablic w rekordach, wygląda to następująco:

  type                                    //Deklaracja rekordu z 2 tablicami 16 elementowymi
  TDane = record
    X : array[1..16] of integer;
    Y : array[1..16] of integer;
  end;

var
    Dane :   TDane;                     //rzutowanie
Begin
    Dane.X[1]:=10;                     //przykład odwołania
End;