Moduły Delphi 6 - wszystko co powinieneś o nich wiedzieć

michalkopacz

<font = 'verdana'>Spis treści
1. Wstęp
2. Typy modułów
2.1 Moduł główny projektu
2.2 Moduł formularza
2.3 Zwykły moduł
3.Budowa modułu
3.1 Budowa i składnia programu (moduł główny projektu)
3.2 Budowa i składnia modułu (zwykły moduł, moduł formularza)
3.2.1 Słowo kluczowe unit
3.2.2 Sekcja interface
3.2.3 Sekcja implementation
3.2.4 Sekcja initialization
3.2.5 Sekcja finalization
4. Zależności między modułami - sekcja uses
4.1 Struktura sekcji uses
4.2 Bezpośrednia i pośrednia zależność między modułami
4.3 Cykliczna zależność między modułami
5. Warsztat
5.1 Quiz
5.2 Ćwiczenia
5.3 Dodatki
A. Odpowiedzi do Quizu
B. Rozszerzenia plików stosowane w Delphi

</span>


1. Wstęp

Object Pascal zaliczany jest do tzw. modularnych języków programowania. Oznacza to, że podstawowym elementem każdego programu jest <b>moduł</b>. Modularna struktura programu pozwala na odpowiednie grupowanie określonych, powiązanych ze sobą części kodu. Kod ten zapisywany jest w pliku tekstowym, czyli module i kompilowany na kod wykonywalny, zrozumiały dla komputera. Każdy moduł jest kompilowany i zapisywany oddzielnie. Aby stworzyć aplikację, skompilowane moduły muszą być połączone. Proces łączenia modułów nazywamy linkowaniem. 

Moduł (ang. unit) to plik tekstowy, który może być kompilowany do postaci kodu wykonywalnego tzn. kod źródłowy tłumaczony jest na język zrozumiały dla komputera.

2. Typy modułów

W Delphi mamy do dyspozycji trzy rodzaje modułów:
  *  Moduł główny projektu (ang. <i>project source unit</i>),
  *  Moduł formularza,
  *  ?Zwykły? moduł (moduł niezwiązany z formularzem).

Aplikacja Delphi z graficznym interfejsem (aplikacja GUI) posiada, co najmniej dwa moduły, moduł główny projektu i moduł formularza głównego. 
Aplikacja GUI (Graphical User Interface) to 32-bitowy program posiadający formularz główny (może posiadać również dodatkowe formularze), na którym znajdują się elementy graficzne takie jak: okna, menu, pola edycyjne, przyciski i wiele innych komponentów, dzięki którym aplikacja staje się łatwiejsza w użyciu. Oprócz aplikacji GUI wyróżniamy również aplikacje terminalowe (konsolowe), uruchamiające się w oknie ?Tryb MS-DOS?.

2.1 Moduł główny projektu

W odróżnieniu od większości tradycyjnych aplikacji tworzonych w Turbo Pascalu, gdzie cały kod źródłowy zawierał się w ?programie głównym?, prawie cały kod aplikacji napisanych w Delphi zawarty jest w modułach, natomiast ?program główny? zredukowany został do roli organizacyjnej. Moduł główny projektu (ang. <i>project source unit</i>) zawiera tekst źródłowy projektu i posiada rozszerzenie <b>.DPR</b> (od <i>Delphi PRoject</i>). Możesz obejrzeć jego zawartość, wybierając z menu opcję <i>Project|View Source</i>.
2.2 Moduł formularza
Drugi typ modułu, który zawsze występuje w aplikacji GUI, to moduł formularza głównego. Moduł formularza, jak sama nazwa wskazuje, zawiera kod źródłowy związany z formularzem. Każdemu formularzowi odpowiada jeden moduł, lecz nie zawsze jest odwrotnie, ponieważ mogą istnieć moduły niereprezentujące formularzy. Pliki modułu formularza mają rozszerzenie <b>.PAS</b>. 

2.3 ?Zwykły? moduł

Istnieje także trzeci typ modułów, które możemy stosować w aplikacjach Delphi. Zawierają one tylko kod źródłowy, wywoływany z innych modułów w projekcie, i nie są związane z formularzami.
3. Budowa modułu
Moduły w Delphi muszą mieć pewien określony format (określoną budowę). Jest to niezbędne, aby kompilator mógł skompilować kod do postaci wykonywalnej.

3.1 Budowa i składnia programu (moduł główny projektu)

Moduł główny projektu zawiera na początku słowo kluczowe <b>program</b>, po którym występuje nazwa modułu, sekcję <b>uses </b>(opcjonalnie) i blok kodu objęty słowami kluczowymi <b>begin</b> i <b>end</b>. Oto przykładowa postać programu głównego Delphi:

Wydruk 1. Kod źródłowy domyślnego projektu Delphi

 1:  program Project1;
 2:
 3:  uses
 4:    Forms,
 5:    Unit1 in 'Unit1.pas' {Form1};
 6:
 7:  {$R *.res}
 8:
 9:  begin
10:    Application.Initialize;
11:    Application.CreateForm(TForm1, Form1);
12:    Application.Run;
13:  end.

Uwaga! Numery linii przedstawione na powyższym wydruku (również na niektórych wydrukach w dalszej części artykułu) nie są częścią kodu; umieściłem je tam po to, aby móc się do nich odwoływać w tekście. W Pascalu nie numeruje się linii kodu źródłowego, w przeciwieństwie do niektórych innych języków programowania (np. starszych wersji Basica).

Linia 1. zawiera słowo <b>program</b>, które wskazuje, iż jest to moduł główny projektu. Bezpośrednio za nim znajduje się nazwa projektu zakończona średnikiem. Nazwa projektu musi być identyczna jak nazwa pliku projektu. W powyższym przykładzie po słowie <b>program</b> występuje nazwa <b>Project1</b>, tak więc plik projektu powinien nazywać się <i>Project1.dpr</i>. W standardowym Pascalu słowo kluczowe <b>program</b> mogło zawierać dodatkowe parametry, które występowały po nazwie programu. Kompilator Object Pascala ignoruje te parametry. Na przykład:
program Calc(input, output);

W linii 3. zaczyna się sekcja uses. Zawiera ona nazwy wszystkich modułów, do których odwołuje się ten moduł. Na przykład w linii 11.:

Application.CreateForm(TForm1, Form1);

jest odwołanie do informacji, której nie ma w module głównym. Procedura Application.CreateForm umieszczona jest w module Forms.pas, natomiast TForm1 i Form1 znajdują się w module głównego formularza Unit1.pas. Sekcja uses informuje Delphi, gdzie ma szukać informacji potrzebnej do skompilowania danego modułu.

uses
  Forms,
  Unit1 in 'Unit1.pas' {Form1};

Zwróć uwagę, że lista ta zawiera nazwy dwóch modułów: Forms i Unit1. Druga linia w tej sekcji jest trochę niestandardowa. Występuje ona tylko w pliku źródłowym modułu głównego i oznacza odwołanie do formularza zawartego w pliku Unit1.pas.
W linii 7. występuje dyrektywa kompilatora, która nakazuje mu dołączenie pliku zasobów projektu (ang. resources) do programu.
Linie od 9. do 13. zawierają blok kodu, który jest ograniczony słowami kluczowymi begin i end. Zauważ, że końcowy end modułu kończy się kropką. W module może występować nieskończenie wiele bloków kodów zawartych pomiędzy begin i end, jednak end z kropką występuje jedynie na końcu modułu. Instrukcje zawarte w liniach od 10. do 12. odpowiedzialne są za inicjalizację programu, utworzenie jego głównego formularza i jego uruchomienie.

3.2 Budowa i składnia modułu (?zwykły? moduł, moduł formularza))

W module zawarte są typy danych (włączając klasy), stałe, zmienne oraz procedury i funkcje. Każdy moduł zapisywany jest w oddzielnym pliku modułu (.PAS).

Plik modułu formularza zaczyna się słowem kluczowym unit (linia 1.), po którym występują sekcje interface (linia 3.), implementation (linia 20.), initialization (linia 24.) i finalization (linia 26.). Sekcje initialization i finalization są opcjonalne (Nowo utworzony moduł formularza nie zawiera sekcji initialization i finalization. Dopisałem je na potrzeby artykułu). Szkielet pliku modułu formularza przedstawia wydruk 2.

Wydruk 2. Szkielet kodu modułu formularza

 1:  unit Unit1;
 2:
 3:  interface
 4:
 5:  uses
 6:    Windows, Messages, SysUtils, Variants, Classes, Graphics,
 7:    Controls, Forms, Dialogs;
 8:
 9:  type
10:    TForm1 = class(TForm)
11:    private
12:      { Private declarations }
13:    public
14:      { Public declarations }
15:    end;
16:
17:  var
18:    Form1: TForm1;
19:
20:  implementation
21:
22:  {$R *.dfm}
23:
24:    initialization
25:
26:  finalization
27:  
28:  end.

Jak wcześniej wspomniałem każdemu formularzowi odpowiada jeden moduł. Poniższy wydruk przedstawia deklarację formularza jako typu:

Wydruk 3. Deklarację formularza jako typu

type
  TForm1 = class(TForm)
  private
      { Private declarations }
  public
      { Public declarations }
end;

Jak łatwo zauważyć, formularz jest obiektem o typie pochodnym w stosunku do typu TForm. Stosowne komentarze wskazują miejsce do wpisania własnych deklaracji ? prywatnych i publicznych.
Wybierając opcję File|New|Unit naszym oczom ukaże się inny typ modułu w Pascalu, nazwany przez zemnie ?zwykłym modułem?. Szkielet tego modułu przedstawia poniższy wydruk:

Wydruk 4. Nowo utworzony moduł

 1:  unit Unit2;
 2:
 3:  interface
 4:
 5:  implementation
 6:
 7:  end.

?Zwykły moduł? różni się od modułu formularza tym, iż jest bardziej ?zubożały?. Zawiera on tylko deklaracje sekcji interface i implementation, oraz nazwę modułu (może on również zawierać sekcje initialization i finalization). Każdy moduł musi być zakończony słowem kluczowym end z kropką.
Bardziej szczegółowy opis poszczególnych składników modułu znajdziesz w poniższych podpunktach.

3.2.1 Słowo kluczowe unit

Bezpośrednio po słowie kluczowym <b>unit</b> występuje nazwa modułu, która jest zakończona średnikiem. Nazwa pliku modułu musi być identyczna jak nazwa modułu. Na przykład w poniższej deklaracji:
unit MainForm;

po słowie unit występuje nazwa MainForm, tak więc plik modułu będzie nazywał się MainForm.pas, a plik skompilowanego modułu MainForm.dcu. Nazwy modułów należących do danego projektu nie mogą być identyczne. Oznacz to, że program nie może zawierać dwóch tak samo nazywających się plików modułu.

3.2.2 Sekcja interface

W module sekcja <b>interface</b> zaczyna się słowem kluczowym <b>interface</b> i kończy się początkiem następnej sekcji, czyli sekcji <b>implementation</b>. W sekcji <b>interface</b> zadeklarowane są stałe, typy, zmienne, funkcje i procedury, które są dostępne dla klientów, czyli modułów, które odwołują się do danego modułu ( w sekcji <b>uses</b> tych modułów zadeklarowany jest dany moduł). Te deklaracje zwane są publicznymi (ang. <i>public</i>), ponieważ klient może używać ich tak, jakby były one zadeklarowane w kliencie. W sekcji <b>interface</b> zadeklarowane są tylko nazwy funkcji lub procedur. Właściwy kod procedur i funkcji znajduje się w sekcji <b>implementation</b>. Poniższy wydruk przedstawia taką deklarację:

Wydruk 5. Deklaracja procedury Button1Click w sekcji interface

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls,
  Forms, Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject); 
    {deklaracja procedury Button1Click w sekcji interface} 
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
{kod procedury Button1Click}
end;

end.

Sekcja ta może zawierać również słowo kluczowe uses, jednak musi ono pojawić się natychmiast po słowie interface.

3.2.3 Sekcja implementation

Sekcja <b>implementation</b> zaczyna się słowem kluczowym <b>implementation</b> i trwa, dopóki nie zacznie się sekcja <b>initialization</b> lub, jeśli nie istnieje sekcja <b>initialization</b>, dopóki nie wystąpi słowo <b>end</b> kończące moduł.

Sekcja ta zawiera definicje (kod właściwy) funkcji i procedur zadeklarowanych w sekcji interface. Sekcja implementation może również zawierać definicje procedur i funkcji, które nie zostały zadeklarowane w sekcji interface, jednakże są to procedury i funkcje prywatne (ang. private), czyli nie dostępne dla klientów. Przykład wyżej opisanych deklaracji przedstawia wydruk 6. :

Wydruk 6. Definicje procedur w sekcji implementation

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls,
  Forms, Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure MojaProcedura; 
    {deklaracja procedury MojaProcedura w sekcji interface} 
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.MojaProcedura; //Procedura publiczna
begin
{definicja (kod) procedury MojaProcedura w sekcji implementation}
end;

procedure MojaProcedura2; //Procedura prywatna
begin
{definicja (kod) procedury MojaProcedura2 w sekcji implementation}
end;

end.

Oprócz definicji funkcji i procedur, sekcja implementation może zawierać również deklaracje stałych, zmiennych i typów danych. Są to deklaracje prywatne, tzn. niedostępne dla klientów. Sekcja implementation może zawierać słowo kluczowe uses (podobnie jak sekcja interface), które występuje po słowie implementation.
Ważnym szczegółem w przedstawionym wydruku 6. jest dyrektywa:

{$R *.dfm}

Służy ona do połączenia modułu z reprezentującym formularz plikiem zasobu o rozszerzeniu .DFM (od Delphi ForM). Gwiazdka zastępująca nazwę pliku nie spełnia tutaj roli szablonu, lecz symbolizuje nazwę modułu. I tak, dla modułu unit1.pas napis *.dfm oznacza to samo, co unit1.dfm.

3.2.4 Sekcja initialization

W sekcji <b>initialization</b> umieszcza się kod, który musi być wykonany w momencie ładowania modułu do pamięci. Sekcja ta jest opcjonalna, co oznacz, że nie musi występować w module. Rozpoczyna się od dyrektywy<b> initialization</b>, a kończy dyrektywą <b>end</b>, kończącą równocześnie cały moduł, bądź też słowem <b>finalization</b>. Kolejność wykonywania części inicjacyjnych (sekcji <b>initialization</b>) poszczególnych modułów zależy od ich wzajemnego uzależnienia wynikającego z dyrektyw <b>uses</b>. 

3.2.5 Sekcja finalization

W sekcji <b>finalization</b> umieszcza się kod wykonywany w chwili usuwania modułu z pamięci. Sekcja <b>finalization</b>, podobnie jak sekcja <b>initialization</b>, jest opcjonalna. Jeżeli jednak występuje w module, to nie wolno pominąć sekcji <b>initialization</b>. Rozpoczyna się od dyrektywy <b>finalization</b> a kończy dyrektywą <b>end</b>, kończącą zarazem cały moduł. Pojawiła się w Delphi 2, zastępując znany z Turbo Pascala mechanizm tzw. funkcji kończących <b>ExitProc</b> (mechanizm ten istniał jeszcze w Delphi 1, wspierany dodatkowo przez funkcję <b>AddExitProc</b>). Część kończąca (sekcja <b>finalization</b>) jest wykonywana przeciwnie do części inicjacyjnej. Na przykład, jeśli aplikacja inicjuje moduły w kolejności <b>A</b>, <b>B</b> i <b>C</b> (litery oznaczają nazwy modułów), to sfinalizuje (zakończy) je w kolejności <b>C</b>, <b>B</b> i <b>A</b>. Przykład kolejności inicjowania i finalizowania modułów przedstawia ćwiczenie 1.

4. Zależności między modułami - sekcja uses

Zależności pomiędzy modułami wynikają z ich wzajemnej deklaracji w sekcji <b>uses</b>. Zanim jednak opiszę te zależności, przedstawię najpierw budowę sekcji <b>uses</b>.

4.1 Struktura sekcji uses

Sekcja <b>uses</b> w module lub programie głównym zawiera listę modułów, do których występują odwołania. Dyrektywa <b>uses </b>może występować w:
  • w pliku projektu programu głównego lub biblioteki,
  • w sekcji interface modułu,
  • w sekcji implementation modułu.
    Najczęściej sekcja uses występuje w module głównym projektu lub części interface. Każdy moduł może zawierać, co najwyżej dwie sekcje uses.
    Sekcja uses zaczyna się słowem kluczowym uses, po którym występuje lista modułów, zakończona średnikiem. Nazwy modułów muszą być oddzielone od siebie przecinkami. Na przykład:
uses Forms, Main;

albo

uses Windows, Messages, SysUtils, Strings, Classes, Unit2, MyUnit;

Nie jest natomiast istotny podział na linie ? poniższe dwie sekcje są dla kompilatora równoważne:

uses 
  SysUtils, Types, Classes, Graphics, Controls;
uses 
  SysUtils, 
  Types, 
  Classes, 
  Graphics, 
  Controls;
W sekcji <b>uses</b> programu (modułu głównego projektu) lub biblioteki może występować nazwa modułu ze słowem <b>in</b>, po którym występuje nazwa pliku modułu, z lub bez ścieżki dostępu, ograniczona pojedynczymi znakami cudzysłowia. Na przykład:
uses 
  Windows, Messages, SysUtils, Strings in 'C:\Classes\Strings.pas',
  Classes;

Ścieżka dostępu do pliku modułu może być względna. Używamy jej wtedy, gdy plik modułu znajduje się w podkatalogu. Na przykład, na poniższym wydruku:

uses
  QForms,
  Main,
  Extra in '../extra/extra.pas';

plik modułu extra.pas znajduje się w katalogu extra, który znajduje się w katalogu projektu.
Dyrektywę in używamy tylko w ostateczności, na przykład wtedy, kiedy plik modułu, do którego odwołujemy się w sekcji uses, znajduje się w innym folderze niż pliki projektu (naszego programu), a ścieżka dostępu do tego modułu nie jest zawarta w ogólnej Bibliotece ścieżek dostępu (tłumaczyłem z ang. general Library search path).
Sekcja uses pozostałych modułów (moduł formularza, ?zwykły? moduł) nie może zawierać dyrektywy in. Ścieżka dostępu do każdego modułu, do którego się odwołujemy w danym module, musi znajdować się w ogólnej Bibliotece ścieżek dostępu, lub wszystkie moduły, do których się odwołujemy, muszą znajdować się w tym samym katalogu, co dany moduł. Ponadto, nazwy modułów muszą byś identyczne jak nazwy plików modułu.
Moduł używany automatycznie przez każdy program to moduł System. Nie jest on jednak deklarowany w sekcji uses w sposób jawny (nazwa tego modułu nie występuje w sekcji uses, jednak program odwołuje się do tego modułu). Inne standartowe moduły, takie jak SysUtils muszą być zadeklarowane w sekcji uses. W większości przypadków, wszystkie potrzebne moduły umieszczane są do sekcji uses podczas tworzenia projektu.

4.2 Bezpośrednia i pośrednia zależność między modułami

Jeżeli moduł <b>A</b> odwołuje się do stałych, zmiennych, typów, procedur i funkcji, które są zawarte w module <b>B</b>, wtedy moduł B musi być zadeklarowany w module <b>A</b> w sposób jawny. Uogólniając, jeżeli nazwa modułu <b>B</b> występuje na liście <b>uses</b> modułu<b> A</b>, to mówimy, że moduł <b>A</b> jest <b>bezpośrednio zależny</b> (ang. <i>direct unit references</i>) od modułu <b>B</b>. Jeżeli w module <b>B</b> na liście <b>uses</b> występuje nazwa <b>C</b>, to moduł<b> A</b> jest <b>zależny pośrednio</b> (ang. <i>indirect unit references</i>) od modułu <b>C</b> ? poprzez moduł <b>B</b>. W takim wypadku nazwa modułu <b>C</b> nie musi zawierać się w sekcji <b>uses</b> modułu <b>A</b>, jednak kompilator musi być zdolny znaleźć moduły <b>B</b> i <b>C</b>, aby mógł skompilować moduł <b>A</b>. Ogólnie rzecz biorąc, opisana zależność pomiędzy modułami może prowadzić przez większą liczbę modułów pośrednich. Poniższy wydruk ilustruje opisane wyżej zależności.

Wydruk 7. Bezpośrednia i pośrednia zależność między modułami

unit A;

interface

uses B;
const a = b;

implementation

end.

  -----------------------------------------------------------------------
unit B;

interface

uses C;
const b = c;

implementation

end.

-----------------------------------------------------------------------
unit C;

  interface

const c = 1;

  implementation

end.
<br>

W powyższym przykładzie moduł A jest zależny bezpośrednio od modułu B, który jest zależny bezpośrednio od modułu C. Tak, więc moduł A jest pośrednio zależny od modułu C. Ponieważ moduł C nie jest zadeklarowany w sekcji uses modułu A, stąd wszystkie stałe, zmienne itp. występujące w module C, nie są dostępne dla modułu A.

4.3 Cykliczna zależność między modułami

Opisana w punkcie 4.2 bezpośrednia zależność między modułami ma bardzo wyraźny aspekt praktyczny. Jeżeli moduł <b>X</b> zależny jest od modułu <b>Y</b> (poprzez deklarację modułu <b>Y</b> w sekcji <b>uses</b> części publicznej (sekcji <b>interface</b>) modułu <b>X</b>), to skompilowanie (przynajmniej) części publicznej modułu <b>Y</b> jest konieczne do tego, by mogła rozpocząć się kompilacja modułu <b>X</b>. Jeżeli więc zdarzy się tak, iż przynajmniej dwa moduły (nazwijmy je <b>P</b> i <b>Q</b>) będą od siebie nawzajem zależne, nie będzie możliwe skompilowanie ani modułu <b>P</b>, ani <b>Q</b>; w efekcie nie będzie możliwe skompilowanie projektu. Takie wzajemne uzależnienie publicznych części modułów nazywamy w Pascalu <b>odwołaniem cyklicznym</b> (ang. <i>circular unit reference</i>); powoduje ono oczywiście błąd kompilacji. Poniższe dwa moduły uwikłane są w odwołanie cykliczne:

Wydruk 8. Cykliczna zależność między modułami

unit P;

interface

uses Q;

implementation

end.

  -----------------------------------------------------------------------
unit Q;

interface

uses P;

implementation

end.

Należy zaznaczyć, iż listy uses w części prywatnej modułów nie powodują opisanego uzależnienia. Wynika stąd prosty wniosek, iż pierwszym krokiem w celu pozbycia się odwołania cyklicznego powinna być próba przeniesienia kolidujących nazw na listach uses z części publicznej do części prywatnej modułów (chodzi oczywiście o te nazwy, które w części publicznej nie są potrzebne i znalazły się tam np. przez niedopatrzenie). Jeżeli nie rozwiąże to problemu, należy stworzyć odrębny moduł i przenieść do jego części publicznej te elementy, które stanowią przyczynę wystąpienia odwołania cyklicznego. Przykład pozbycia się cyklicznej zależności miedzy modułami przedstawia poniższy wydruk:

Wydruk 9. Przykład pozbycia się odwołania cyklicznego

unit P;

interface

uses Q;

implementation

end.

  -----------------------------------------------------------------------
unit Q;

interface

implementation

uses P;

end.

5. Warsztat

Warsztat składa się z pytań kontrolnych oraz ćwiczeń utrwalających i pogłębiających zdobytą wiedzę. W razie trudności lub wątpliwości, odpowiedzi na pytania Quizu zamieszczone są w dodatku A.

5.1 Quiz

Quiz składa się z dziesięciu pytań zamkniętych. Spośród odpowiedzi A, B i C tylko jedna jest prawidłowa.

1. Jakie jest rozszerzenie pliku zawierającego moduł Object Pascala?
A) .dcu
B) .pas
C) .dpr

2. Ile modułów głównych projektu może zawierać pojedynczy program?
A) tylko jeden
B) nieskończenie wiele
C) to zależy od rodzaju tworzonego programu

3. Który rodzaj modułu nie posiada sekcji interface?
A) moduł główny projektu
B) moduł formularza
C) ?zwykły? moduł

4. Sekcja implementation nazywana jest również:
A) częścią publiczną modułu
B) częścią chronioną modułu
C) częścią prywatną modułu

5. Sekcja uses zawiera nazwy modułów, do których występują odwołania. Każdy moduł może zawierać co najwyżej:
A) jedną sekcje uses
B) dwie sekcje uses
C) trzy sekcje uses

6. Która z poniższych zależności miedzy modułami jest przyczyną niemożliwości kompilacji programu?
A) pośrednia zależność między modułami
B) bezpośrednia zależność między modułami
C) cykliczna zależność między modułami

7. Proces łączenia modułów nazywamy:
A) kompilacją
B) linkowaniem
C) replikacją

8. Sekcja uses nie może występować w:

A) sekcji interface modułu
B) sekcji initialization modułu
C) w module głównym biblioteki

9. W sekcji implementation mogą wstępować:

A) definicje (kod właściwy) funkcji i procedur
B) deklaracje nagłówków funkcji i procedur
C) definicje i deklaracje funkcji i procedur

10. Aplikacja konsolowa to :
A) aplikacja z graficznym interfejsem, zwana również aplikacją GUI
B) 16-bitowy program działający zarówno w systemie operacyjnym Windows, jak również w systemie Linux
C) aplikacja terminalowa, działająca w systemie MS-DOS

5.2 Ćwiczenia

Najlepszą metodą pogłębienia i opanowania zdobytej wiedzy jest praktyka. Poniżej zamieszczam 2 ćwiczenia, które, mam nadzieję, utrwalą zdobyte wiadomości na temat struktury modułów.

Ćwiczenie 1

Zagadnienie: Sekcje initialization i finalization

Pierwsze ćwiczenie ma na celu opanowanie kolejności inicjowania i finalizowania poszczególnych modułów. A więc do dzieła:

1.Poleceniem menu File|New|Other|Console Aplication stwórz nowy projekt programu, który będziemy testować w okienku tekstowym.
2.Dodaj do projektu dwa moduły. W tym celu dwukrotnie wykonaj polecenie File|New|Unit.
3.Poleceniem menu File|Save All zapisz projekt na dysku. Nazwę modułu projektu pozostaw bez zmian. Dodane moduły nazwij kolejno UnitA.pas oraz UnitB.pas.
4.Nie pozostaje nam nic innego, jak poszczególne zakładki wypełnić kodem przedstawionym na poniższych wydrukach.

program Project1;

{$APPTYPE CONSOLE}

uses
  UnitA;

begin
  WriteLN('Program glowny');
  Write('Nacisnij klawisz ... ');
  ReadLN;
end.


unit UnitA;

interface
uses 
  UnitB;

implementation

initialization
  WriteLN('Inicjacja modulu A');

finalization
  WriteLN('Finalizacja modulu A');
  Write('Nacisnij klawisz ... ');
  ReadLN;

end.


unit UnitB;

interface 

implementation

initialization
  WriteLN('Inicjacja modulu B');

finalization
  WriteLN('Finalizacja modulu B');
  Write('Nacisnij klawisz ... ');
  ReadLN;

end.
  1. Zapisz ponownie projekt (File|Save All).
    7.Skompiluj i uruchom program poleceniem menu Project|Run.

    Analizując zapisy przedstawione na wydrukach oraz porównując je z wynikiem działania aplikacji, bez problemu zauważymy, w jakiej kolejności inicjowane i finalizowane są w programie poszczególne moduły.

Ćwiczenie 2

Zagadnienie: Odwołania cykliczne

W tym ćwiczeniu zademonstruję program uwikłany w odwołanie cykliczne. Pokażę również, jak pozbyć się cyklicznej zależności między modułami.

1.Poleceniem menu File|New|Other|Console Aplication stwórz nową aplikację konsolową.
2.Dodaj do projektu dwa moduł (File|New|Unit).
3.Poleceniem menu File|Save All zapisz projekt na dysku. Nazwy modułów oraz programu pozostaw domyślne.
4.Wypełnij moduły kodem przedstawionym na poniższych wydrukach.

program Project1;

{$APPTYPE CONSOLE}

uses
  Unit1;

begin
  WriteLN('Jesli ten program sie uruchomil, to znaczy,'); 

  WriteLN('ze pozbyles sie odwolania cyklicznego.'); 
  Write('Nacisnij klawisz ... ');
  ReadLN;
end.


unit Unit1;

interface
uses 
  Unit2;

implementation
    
end.


unit Unit2;

interface 
uses 
  Unit1;

implementation

end.

5.Zapisz ponownie projekt (File|Save All).
6.Skompiluj i uruchom program poleceniem menu Project|Run. I tu spotyka Cię niespodzianka. Program nie uruchomi się, ponieważ kompilator sygnalizuje błąd:

[Fatal Error] Unit2.pas(4): Circular unit reference to 'Unit2'

Powyższy błąd oznacza, że między modułem Unit1, a modułem Unit2 zachodzi odwołanie cykliczne. Aby zlikwidować błąd i tym samym pozbyć się odwołania cyklicznego, wykonaj poniższe czynności:

7.Przenieś sekcję uses z sekcji interface do sekcji implementation w module Unit2. Po wykonaniu tej czynności kod w module Unit2 powinien wyglądać tak, jak na poniższym wydruku.

unit Unit2;

interface 

implementation
uses 
  Unit1;

end.

8.Uruchom teraz program. Jeśli wyświetli się okienko tekstowe to znaczy, że pozbyłeś się odwołania cyklicznego.

Zademonstrowałem tu tylko jeden sposób pozbycia się odwołania cyklicznego. Można było również pozbyć się deklaracji modułu Unit1 w sekcji uses modułu Unit2.

5.3 Dodatki

A. Odpowiedzi do Quizu

Pyt. Odp.
1 B
2 A
3 A
4 C
5 A
6 C
7 B
8 B
9 A
10 C

B. Rozszerzenia plików stosowane w Delphi


Element Rozszerzenie Pełna nazwa

Plik projektu .DPR Delphi Project
Plik grupy projektowej .BPG Borland Project Group
Plik kodu źródłowego .PAS Pascal
Plik formularza .DFM Delphi Form Module
Skompilowany plik modułu .DCU Delphi Compiled Module
Skompilowany plik zasobów .RES / .DCR Resource / Delphi Compiled Resource
Zapisane ustawienia pulpitu .DSK Desktop
Ustawienia projektu .DOF Delphi Options File
Pliki źródłowe pakietu .DPK Delphi Package
Skompilowany pakiet .BPL Borland Package Libraries
Układ pulpitu .DST Desktop Settings
Plik opcji kompilatora
aplikacji konsolowej .CFG Configuration
Dołączony kod źródłowy .INC Include

Autor: Michał Kopacz
E-mail: michalkopacz@o2.pl

</p>

7 komentarzy

Nazwa modułu A w module B, w sekcji:

  • interface: moduł A widoczny na zewnątrz modułu B
  • implementation: moduł A niewidoczny na zewnątrz modułu B

O widoczności mówimy wtedy, gdy moduł A jest włączony do innego modułu np.: C.

A co to za różnica, czy się napisze uses [nazwa modułu] w interface, czy się napisze to w implementation

2.1 Moduł główny projektu
2.2 Moduł formularza
2.3 ?Zwykły? moduł

Skąd to wziąłeś :D
Moduł (.PAS) to jedno, a program (.DPR) to co innego...

Artykul pierwsza klasa

edytowalem ci artykul i dodalem linki=kotwice, zeby bylo latwiej sie poruszac po artykule...
Sugestia - edytuj go i dopisz linki w calym spisie tresci.

Jezeli jestes autorem tego tesktu to ocena 6

Napiszcie co myslicie o tym artykule.
Zobaczcie również artykuły:
"Zamykanie systemu w Delphi".
"Funkcje generatora liczb pseudolosowych"
Autor.

Dobry artykul, wszystko dokladnie opisane.