Dalam proses menggunakan DELPHI untuk mengembangkan perangkat lunak, kami seperti sekelompok sapi dan domba yang bahagia di padang rumput, dengan hati-hati menikmati sinar matahari yang dibawakan oleh bahasa Object Pascal dan kekayaan tanaman air yang disediakan oleh berbagai kontrol VCL. Menatap langit biru yang tak berbatas, menatap rerumputan hijau subur di bumi, siapa sangka betapa besarnya alam semesta dan benda apa saja yang lebih kecil dari molekul dan atom? Itu adalah urusan para filsuf. Pada saat ini, sang filsuf sedang duduk di puncak gunung yang tinggi, memandangi perubahan nebula alam semesta, menatap serangga yang merayap di tanah, tiba-tiba berbalik, mengangguk dan tersenyum pada kelompok penggembalaan kami. sapi dan domba. Dia mengambil sebatang rumput, memasukkannya dengan lembut ke dalam mulutnya, menutup matanya dan mencicipinya dengan hati-hati. Entah apa rasa rumput ini di mulut sang filsuf? Namun, senyum puas selalu terpampang di wajahnya.
Mengetahui dan memahami dunia atom mikroskopis DELPHI dapat memungkinkan kita memahami secara menyeluruh struktur aplikasi makroskopis DELPHI, sehingga mengembangkan perangkat lunak kita dalam ruang ideologis yang lebih luas. Ibarat Newton yang menemukan gerak benda makroskopik, namun ia kesusahan karena tidak tahu mengapa benda itu bergerak seperti ini. Sebaliknya, Einstein mengalami kehidupan bahagia relativitas antara hukum partikel dasar dan gerak benda makroskopik !
Bagian 1 TObjek Atom
Apa itu TObject?
Ini adalah inti dasar arsitektur bahasa Object Pascal dan asal mula berbagai kontrol VCL. Kita dapat menganggap TObject sebagai salah satu atom yang membentuk aplikasi DELPHI. Tentu saja, mereka terdiri dari partikel yang lebih halus seperti elemen sintaksis dasar Pascal.
Dikatakan TObject merupakan atom dari program DELPHI karena TObject didukung secara internal oleh compiler DELPHI. Semua kelas objek diturunkan dari TObject, meskipun Anda tidak menentukan TObject sebagai kelas leluhur. TObject didefinisikan dalam unit Sistem, yang merupakan bagian dari sistem. Di awal unit System.pas, ada teks komentar ini:
{Konstanta, tipe, prosedur yang telah ditentukan sebelumnya, }
{ dan fungsi (seperti True, Integer, atau }
{Writeln) tidak memiliki deklarasi sebenarnya.}
{ Sebaliknya mereka dibangun ke dalam kompiler }
{ dan diperlakukan seolah-olah telah dideklarasikan }
{ di awal unit Sistem.}
Artinya, unit ini berisi konstanta, tipe, prosedur, dan fungsi yang telah ditentukan sebelumnya (seperti: True, Integer, atau Writeln). menjadi definisi yang dinyatakan. Anda dapat menambahkan file program sumber lain seperti Classes.pas atau Windows.pas ke file proyek Anda untuk mengkompilasi dan men-debug kode sumber, tetapi Anda sama sekali tidak dapat menambahkan file program sumber System.pas ke file proyek Anda untuk kompilasi! DELPHI akan melaporkan kesalahan kompilasi untuk definisi duplikat Sistem!
Oleh karena itu, TObject adalah definisi yang disediakan secara internal oleh compiler. Bagi kita yang menggunakan DELPHI untuk mengembangkan program, TObject adalah sebuah hal yang bersifat atom.
Pengertian TObject pada unit Sistem adalah sebagai berikut:
TObject = kelas
konstruktor Buat;
prosedur Gratis;
fungsi kelas InitInstance(Instance: Pointer): TObject;
prosedur CleanupInstance;
fungsi Tipe Kelas: TClass;
fungsi kelas Nama Kelas: ShortString;
fungsi kelas ClassNameIs(Nama const: string): Boolean;
fungsi kelas ClassParent: TClass;
fungsi kelas ClassInfo: Pointer;
fungsi kelas InstanceSize: Longint;
fungsi kelas InheritsFrom(AClass: TClass): Boolean;
fungsi kelas MethodAddress (Nama const: ShortString): Pointer;
fungsi kelas MethodName (Alamat: Pointer): ShortString;
fungsi FieldAddress (Nama const: ShortString): Pointer;
fungsi GetInterface(const IID: TGUID; keluar Obj): Boolean;
fungsi kelas GetInterfaceEntry(const IID: TGUID): PInterfaceEntry;
fungsi kelas GetInterfaceTable: PInterfaceTable;
fungsi SafeCallException(ExceptObject: TObject;
KecualiAddr: Pointer): HResult virtual;
prosedur Setelah Konstruksi;
prosedur Sebelum Penghancuran;
prosedur Pengiriman(var Pesan);
prosedur DefaultHandler(var Pesan);
fungsi kelas NewInstance: TObject virtual;
prosedur FreeInstance;
destruktor Hancurkan;
akhir;
Selanjutnya, kita secara bertahap akan mengetuk pintu atom TObject untuk melihat struktur apa yang ada di dalamnya.
Kita tahu bahwa TObject adalah kelas dasar dari semua objek, jadi apa sebenarnya objek itu?
Objek apa pun di DELPHI adalah sebuah pointer, yang menunjukkan ruang yang ditempati oleh objek tersebut di memori! Meskipun objeknya adalah sebuah pointer, ketika kita merujuk ke anggota objek tersebut, kita tidak perlu menulis kode MyObject^.GetName, tetapi hanya dapat menulis MyObject.GetName Ini adalah sintaks yang diperluas dari bahasa Object Pascal dan didukung oleh kompiler. Teman-teman pengguna C++ Builder sudah sangat paham tentang hubungan antara objek dan pointer, karena objek di C++ Builder harus didefinisikan sebagai pointer. Tempat yang ditunjuk oleh penunjuk objek adalah ruang objek tempat objek menyimpan data. Mari kita menganalisis struktur data ruang memori yang ditunjuk oleh penunjuk objek.
4 byte pertama dari ruang objek menunjuk ke tabel alamat metode virtual (VMT?C Virtual Method Table) dari kelas objek. Ruang berikutnya adalah ruang untuk menyimpan data anggota objek itu sendiri, dan disimpan dalam urutan total dari data anggota kelas leluhur paling primitif objek hingga data anggota kelas objek, dan dalam urutan di mana anggota data ditentukan di setiap tingkat kelas.
Tabel metode virtual (VMT) suatu kelas menyimpan alamat prosedur metode virtual semua kelas yang berasal dari kelas leluhur asli kelas tersebut. Metode virtual suatu kelas adalah metode yang dideklarasikan dengan kata khusus virtual. Metode virtual adalah mekanisme dasar untuk mencapai polimorfisme objek. Meskipun metode dinamis yang dideklarasikan dengan kata khusus dinamis juga dapat mencapai polimorfisme objek, metode tersebut tidak disimpan dalam tabel alamat metode virtual (VMT). Ini hanyalah metode lain yang disediakan oleh Object Pascal yang dapat menghemat ruang penyimpanan kelas. tetapi dengan mengorbankan kecepatan panggilan.
Bahkan jika kita tidak mendefinisikan metode virtual apa pun dari kelas itu sendiri, objek kelas tersebut masih memiliki penunjuk ke tabel alamat metode virtual, tetapi panjang entri alamatnya nol. Namun, di mana metode virtual yang ditentukan di TObject, seperti Destroy, FreeInstance, dll., disimpan? Ternyata alamat metodenya disimpan dalam spasi yang diimbangi dengan arah negatif relatif terhadap penunjuk VMT. Faktanya, ruang data yang diimbangi sebesar 76 byte ke arah negatif dari tabel VMT adalah struktur data sistem kelas objek. Struktur data ini terkait dengan kompiler dan dapat diubah di versi DELPHI yang akan datang.
Oleh karena itu, Anda dapat berpikir bahwa VMT adalah struktur data yang dimulai dari ruang alamat offset negatif. Area data offset negatif adalah area data sistem VMT, dan data offset positif VMT adalah area data pengguna (metode virtual yang disesuaikan). tabel alamat). Fungsi dan prosedur yang terkait dengan informasi kelas atau informasi runtime objek yang ditentukan dalam TObject umumnya terkait dengan data sistem VMT.
Data VMT mewakili sebuah kelas. Faktanya, VMT adalah sebuah kelas! Di Object Pascal, kami menggunakan pengidentifikasi seperti TObject, TComponent, dll. untuk mewakili kelas, yang diimplementasikan sebagai data VMT masing-masing secara internal di DELPHI. Tipe kelas yang didefinisikan dengan kelas kata yang dicadangkan sebenarnya adalah penunjuk ke data VMT yang relevan.
Untuk aplikasi kita, data VMT adalah data statis. Setelah kompiler mengkompilasi aplikasi kita, informasi data ini telah ditentukan dan diinisialisasi. Pernyataan program yang kita tulis dapat mengakses informasi terkait VMT, memperoleh informasi seperti ukuran objek, nama kelas atau data atribut run-time, atau memanggil metode virtual atau membaca nama dan alamat metode, dll.
Ketika suatu objek dihasilkan, sistem akan mengalokasikan ruang memori untuk objek tersebut dan mengaitkan objek tersebut dengan kelas yang relevan. Oleh karena itu, 4 byte pertama dalam ruang data yang dialokasikan untuk objek tersebut menjadi penunjuk ke penunjuk data kelas VMT.
Mari kita lihat bagaimana benda dilahirkan dan mati. Melihat anak saya yang berumur tiga tahun melompat-lompat di atas rumput, justru karena saya telah menyaksikan proses kelahiran kehidupan maka saya dapat benar-benar memahami arti dan keagungan hidup. Hanya mereka yang pernah mengalami kematian yang akan lebih memahami dan menghargai kehidupan. Jadi, mari kita pahami proses penciptaan dan pemusnahan suatu benda!
Kita semua tahu bahwa objek paling sederhana dapat dibangun dengan menggunakan pernyataan berikut:
AnObject := TObject.Buat;
Kompiler mengimplementasikan kompilasinya sebagai:
Berdasarkan VMT yang terkait dengan TObject, panggil konstruktor Buat TObject. Konstruktor Create memanggil proses ClassCreate sistem, dan proses ClassCreate sistem memanggil metode virtual NewInstance melalui kelas VMT yang disimpan di dalamnya. Tujuan pemanggilan metode NewInstance adalah untuk menetapkan ruang instan objek. Karena kita belum membebani metode ini secara berlebihan, maka ini adalah NewInstance dari kelas TObject. Metode NewInstance dari kelas TObjec akan memanggil prosedur GetMem untuk mengalokasikan memori untuk objek berdasarkan ukuran instance objek (InstanceSize) yang diinisialisasi oleh kompiler dalam tabel VMT, dan kemudian memanggil metode InitInstance untuk menginisialisasi ruang yang dialokasikan. Metode InitInstance pertama-tama menginisialisasi 4 byte pertama ruang objek sebagai penunjuk ke VMT yang sesuai dengan kelas objek, lalu mengosongkan ruang yang tersisa. Setelah membuat instance objek, metode virtual AfterConstruction juga dipanggil. Terakhir, simpan penunjuk alamat data instance objek ke variabel AnObject, dan dengan cara ini, objek AnObject akan lahir.
Demikian pula, suatu objek dapat dimusnahkan menggunakan pernyataan berikut:
AnObject.Hancurkan;
Destruktor TObject, Destroy, dideklarasikan sebagai metode virtual, yang juga merupakan salah satu metode virtual yang melekat pada sistem. Metode Destory pertama-tama memanggil metode virtual BeforeDestruction, lalu memanggil proses ClassDestroy sistem. Proses ClassDestory memanggil metode virtual FreeInstance melalui kelas VMT, dan metode FreeInstance memanggil proses FreeMem untuk melepaskan ruang memori objek. Begitu saja, sebuah objek menghilang dari sistem.
Proses penghancuran suatu benda lebih sederhana dibandingkan dengan proses pembuatan suatu benda, seperti halnya kelahiran kehidupan yang merupakan proses kehamilan yang panjang, namun kematian relatif berumur pendek. Hal ini sepertinya merupakan aturan yang tidak bisa dihindari.
Selama proses konstruksi dan penghancuran objek, dua fungsi virtual, NewInstance dan FreeInstance, dipanggil untuk membuat dan melepaskan ruang memori dari instance objek. Alasan mengapa kedua fungsi ini dideklarasikan sebagai fungsi virtual adalah untuk memungkinkan pengguna memiliki ruang untuk ekspansi ketika menulis kelas objek khusus yang mengharuskan pengguna untuk mengelola memori mereka sendiri (seperti dalam beberapa program kontrol industri khusus).
Mendeklarasikan AfterConstruction dan BeforeDestruction sebagai fungsi virtual juga untuk memberikan kelas turunan di masa depan kesempatan untuk membiarkan objek yang baru lahir menghirup udara segar pertama setelah menghasilkan objek, dan untuk memungkinkan objek menyelesaikan setelahnya sebelum objek tersebut mati. Ini semua Sesuatu yang masuk akal. Faktanya, kejadian OnCreate dan kejadian OnDestroy dari objek TForm dan objek TDataModule dipicu masing-masing dalam dua proses fungsi virtual kelebihan beban TForm dan TDataModule.
Selain itu, TObjec juga menyediakan metode Gratis, yang bukan merupakan metode virtual. Metode ini disediakan khusus untuk melepaskan objek dengan aman ketika tidak jelas apakah objek tersebut kosong (nihil). Faktanya, jika Anda tidak dapat mengetahui apakah objek tersebut kosong, ada masalah logika program yang tidak jelas. Namun, tidak ada orang yang sempurna dan bisa membuat kesalahan. Ada baiknya juga menggunakan Gratis untuk menghindari kesalahan yang tidak disengaja. Namun, menulis program yang benar tidak bisa hanya mengandalkan solusi tersebut. Tujuan pertama pemrograman harus memastikan kebenaran logis dari program tersebut!
Teman-teman yang tertarik dapat membaca kode asli dari unit Sistem, dimana sejumlah besar kode ditulis dalam bahasa assembly. Teman yang berhati-hati dapat menemukan bahwa konstruktor TObject Create dan destructor Destory belum menulis kode apa pun. Faktanya, melalui jendela Debug CPU dalam keadaan debugging, kode perakitan Create dan Destory dapat tercermin dengan jelas. Karena para master yang menciptakan DELPHI tidak ingin memberikan terlalu banyak hal rumit kepada pengguna. Mereka ingin pengguna menulis aplikasi berdasarkan konsep sederhana dan menyembunyikan pekerjaan rumit di dalam sistem untuk mereka lakukan. Oleh karena itu, ketika menerbitkan unit System.pas, kode dari kedua fungsi ini secara khusus dihapus untuk membuat pengguna berpikir bahwa TObject adalah sumber dari segala sesuatu, dan kelas turunan pengguna sepenuhnya dimulai dari ketiadaan. Meskipun membaca kode-kode DELPHI yang paling penting ini memerlukan sedikit pengetahuan bahasa assembly, membaca kode-kode tersebut dapat memberi kita pemahaman yang lebih dalam tentang asal usul dan perkembangan dunia DELPHI. Sekalipun Anda tidak memahami banyak hal, setidaknya memahami beberapa hal dasar akan sangat membantu kami dalam menulis program DELPHI.
Bagian 2 TClass Atom
Di unit System.pas, TClass didefinisikan seperti ini:
TClass = kelas TObject;
Artinya TClass adalah kelas dari TObject. Karena TObject sendiri adalah sebuah kelas, TClass disebut sebagai kelas dari kelas.
Secara konseptual, TClass adalah tipe kelas, yaitu kelas. Namun, kita tahu bahwa kelas DELPHI mewakili sebagian data VMT. Oleh karena itu, kelas dapat dianggap sebagai tipe yang ditentukan untuk item data VMT. Faktanya, ini adalah tipe penunjuk yang menunjuk ke data VMT!
Dalam bahasa C++ tradisional sebelumnya, tipe kelas tidak dapat ditentukan. Setelah objek dikompilasi, objek tersebut diperbaiki, informasi struktural kelas telah diubah menjadi kode mesin absolut, dan informasi kelas yang lengkap tidak akan ada di memori. Beberapa bahasa berorientasi objek tingkat tinggi dapat mendukung akses dinamis dan pemanggilan informasi kelas, namun seringkali memerlukan mekanisme interpretasi internal yang kompleks dan lebih banyak sumber daya sistem. Bahasa Object Pascal DELPHI menyerap beberapa fitur luar biasa dari bahasa berorientasi objek tingkat tinggi, sambil tetap mempertahankan keunggulan tradisional dalam mengkompilasi program secara langsung ke dalam kode mesin, yang secara sempurna memecahkan masalah fungsi lanjutan dan efisiensi program.
Justru karena DELPHI menyimpan informasi kelas yang lengkap dalam aplikasi sehingga DELPHI dapat menyediakan fungsi berorientasi objek tingkat lanjut seperti as dan is untuk mengonversi dan mengidentifikasi kelas saat runtime, di mana data VMT kelas tersebut memainkan peran inti yang penting. Teman-teman yang berminat dapat membaca dua proses perakitan AsClass dan IsClass di unit Sistem, yang merupakan kode implementasi dari operator as dan is untuk memperdalam pemahaman tentang kelas dan data VMT.
...
Konten berikut juga mencakup pengertian konstruktor fiktif, mekanisme implementasi Antarmuka dan mekanisme implementasi penanganan pengecualian, dll. Prinsip dasar DLPHI. Saya harap saya bisa menyelesaikannya setelah May Day dan menyumbangkannya kepada semua orang.