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 ruang objek mengarah ke tabel alamat metode virtual (VMT – Tabel Metode Virtual) 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 kematian 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 ke 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 daripada 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.
Dunia Atom DELPHI (2)
Kata Kunci: Delphi mengendalikan bermacam-macam
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.
Dengan tipe kelas, Anda bisa menggunakan kelas sebagai variabel. Variabel kelas dapat dipahami sebagai objek khusus, dan Anda dapat mengakses metode variabel kelas seperti halnya objek. Sebagai contoh: Mari kita lihat potongan program berikut:
jenis
TSampleClass = kelas TSampleObject;
TSampleObject = kelas( TObject )
publik
konstruktor Buat;
destruktor Hancurkan;
fungsi kelas GetSampleObjectCount:Integer;
prosedur GetObjectIndex:Integer;
akhir;
var
aSampleClass : TSampleClass;
aKelas : Kelas T;
Dalam kode ini, kita mendefinisikan kelas TSampleObject dan tipe kelas terkaitnya TSampleClass, serta dua variabel kelas aSampleClass dan aClass. Selain itu, kami juga mendefinisikan konstruktor, destruktor, metode kelas GetSampleObjectCount, dan metode objek GetObjectIndex untuk kelas TSampleObject.
Pertama, mari kita pahami arti variabel kelas aSampleClass dan aClass.
Jelas, Anda dapat memperlakukan TSampleObject dan TObject sebagai nilai konstan dan menugaskannya ke variabel aClass, sama seperti menetapkan 123 nilai konstan ke variabel integer i. Oleh karena itu, hubungan antara tipe kelas, kelas, dan variabel kelas adalah hubungan antar tipe, konstanta, dan variabel, tetapi pada level kelas, bukan pada level objek. Tentu saja, tidak sah untuk menetapkan TObject secara langsung ke aSampleClass, karena aSampleClass adalah variabel kelas dari kelas TSampleObject yang diturunkan dari TObject, dan TObject tidak berisi semua definisi yang kompatibel dengan tipe TSampleClass. Sebaliknya, sah untuk menetapkan TSampleObject ke variabel aClass, karena TSampleObject adalah kelas turunan dari TObject dan kompatibel dengan tipe TClass. Ini persis sama dengan hubungan penugasan dan pencocokan tipe variabel objek.
Lalu, mari kita lihat apa itu metode kelas.
Yang disebut metode kelas mengacu pada metode yang dipanggil di tingkat kelas, seperti metode GetSampleObjectCount yang didefinisikan di atas, yang merupakan metode yang dideklarasikan dengan kelas kata yang dicadangkan. Metode kelas berbeda dengan metode objek yang dipanggil pada tingkat objek. Metode objek sudah tidak asing lagi bagi kita, dan metode kelas selalu digunakan pada tingkat mengakses dan mengendalikan karakteristik umum semua objek kelas dan mengelola objek secara terpusat. Dalam definisi TObject, kita dapat menemukan sejumlah besar metode kelas, seperti ClassName, ClassInfo, NewInstance, dll. Diantaranya, NewInstance juga didefinisikan sebagai virtual, yaitu metode kelas virtual. Ini berarti Anda dapat menulis ulang metode implementasi NewInstance dalam subkelas turunan untuk membuat instance objek kelas tersebut dengan cara khusus.
Anda juga dapat menggunakan pengidentifikasi self dalam metode kelas, tetapi maknanya berbeda dengan self dalam metode objek. Self dalam metode kelas mewakili kelasnya sendiri, yaitu penunjuk ke VMT, sedangkan self dalam metode objek mewakili objek itu sendiri, yaitu penunjuk ke ruang data objek. Meskipun metode kelas hanya dapat digunakan pada tingkat kelas, Anda masih dapat memanggil metode kelas melalui suatu objek. Misalnya, metode kelas ClassName dari objek TObject dapat dipanggil melalui pernyataan aObject.ClassName, karena 4 byte pertama dalam ruang data objek yang ditunjuk oleh penunjuk objek adalah penunjuk ke kelas VMT. Sebaliknya, Anda tidak dapat memanggil metode objek di tingkat kelas, dan pernyataan seperti TObject.Free harus ilegal.
Perlu dicatat bahwa konstruktor adalah metode kelas, dan destruktor adalah metode objek!
Apa? Konstruktor adalah metode kelas dan destruktor adalah metode objek! Apakah ada kesalahan?
Soalnya, saat Anda membuat objek, Anda jelas menggunakan pernyataan seperti berikut:
aObject := TObject.Buat;
Ini jelas memanggil metode Create dari kelas TObject. Saat menghapus objek, gunakan pernyataan berikut:
aObject.Hancurkan;
Bahkan jika Anda menggunakan metode Gratis untuk melepaskan objek, metode Penghancuran objek akan dipanggil secara tidak langsung.
Alasannya sangat sederhana. Sebelum objek dibangun, objek tersebut belum ada, hanya kelas yang ada. Sebaliknya, menghapus suatu objek harus menghapus objek yang ada, bukan kelasnya.
Terakhir, mari kita bahas masalah konstruktor fiktif.
Dalam bahasa C++ tradisional, destruktor virtual dapat diimplementasikan, namun mengimplementasikan konstruktor virtual adalah masalah yang sulit. Sebab, dalam bahasa C++ tradisional, tidak ada tipe kelas. Contoh objek global ada di ruang data global pada waktu kompilasi, dan objek fungsi lokal juga merupakan contoh yang dipetakan dalam ruang tumpukan pada waktu kompilasi. Bahkan objek yang dibuat secara dinamis ditempatkan dalam struktur kelas tetap menggunakan operator baru yang dialokasikan di ruang heap, dan konstruktor hanyalah metode objek yang menginisialisasi instance objek yang dihasilkan. Tidak ada metode kelas nyata dalam bahasa C++ tradisional. Meskipun apa yang disebut metode berbasis kelas statis dapat didefinisikan, metode tersebut pada akhirnya diimplementasikan sebagai fungsi global khusus, belum lagi metode kelas virtual hanya dapat menargetkan objek tertentu contoh. efisien. Oleh karena itu, bahasa C++ tradisional percaya bahwa sebelum instance objek tertentu dihasilkan, tidak mungkin membuat objek itu sendiri berdasarkan objek yang akan dihasilkan. Memang tidak mungkin, karena hal ini akan menciptakan paradoks logika yang saling bertentangan!
Namun, justru karena konsep kunci informasi tipe kelas dinamis, metode kelas virtual, dan konstruktor yang diimplementasikan berdasarkan kelas di DELPHI maka konstruktor virtual dapat diimplementasikan. Objek dihasilkan oleh kelas. Objek itu seperti bayi yang sedang tumbuh, dan kelas adalah ibunya. Bayi itu sendiri tidak mengetahui akan menjadi orang seperti apa dia di masa depan, tetapi para ibu menggunakan metode pendidikannya sendiri untuk membina anak-anak yang berbeda. .Teman-teman, prinsipnya sama.
Dalam definisi kelas TComponent konstruktor Create didefinisikan sebagai virtual sehingga berbagai jenis kontrol dapat mengimplementasikan metode konstruksinya sendiri. Inilah kehebatan konsep seperti kelas yang dibuat oleh TClass, dan juga kehebatan DELPHI.
................................................. ..
Bab 3 Pemandangan Ruang dan Waktu di WIN32
Ayah saya yang sudah tua memandangi cucu kecilnya yang sedang bermain dengan mainan di tanah, lalu berkata kepada saya: "Anak ini sama seperti kamu ketika kamu masih kecil. Dia suka membongkar barang-barang dan hanya berhenti setelah melihatnya sampai akhir. " Mengingat kembali masa kecil saya, saya sering membongkar mobil mainan, jam weker kecil, kotak musik, dll, dan sering dimarahi oleh ibu saya.
Pertama kali saya memahami prinsip dasar komputer berkaitan dengan kotak musik yang saya bongkar. Itu ada di buku komik ketika saya masih di sekolah menengah. Seorang lelaki tua berjanggut putih sedang menjelaskan teori mesin pintar, dan seorang paman berkumis sedang berbicara tentang komputer dan kotak musik. Mereka mengatakan bahwa unit pengolah pusat komputer adalah deretan buluh musik yang digunakan untuk pengucapan di dalam kotak musik, dan program komputer adalah benjolan padat pada silinder kecil di dalam kotak musik untuk perputaran unit pemrosesan pusat. Pergerakan alami dari penunjuk instruksi, sedangkan tonjolan yang mewakili musik pada silinder kecil mengontrol getaran buluh musik untuk menghasilkan instruksi yang setara dengan eksekusi program oleh prosesor pusat. Kotak musik mengeluarkan melodi yang indah, yang dimainkan sesuai dengan partitur musik yang telah diukir pada silinder kecil oleh pengrajinnya. Komputer menyelesaikan pemrosesan yang rumit berdasarkan program yang telah diprogram sebelumnya oleh pemrogram. Setelah saya kuliah, saya mengetahui bahwa lelaki tua berjanggut putih itu adalah raksasa ilmiah Turing. Teorinya tentang automata terbatas mendorong perkembangan seluruh revolusi informasi, dan paman berkumis itu adalah bapak komputer, von Neumann. Arsitektur komputer masih menjadi struktur arsitektur utama komputer. Kotak musiknya tidak dibongkar sia-sia, ibu bisa yakin.
Hanya dengan pemahaman yang sederhana dan mendalam kita dapat menciptakan kreasi yang mendalam dan ringkas.
Dalam bab ini kita akan membahas konsep dasar yang terkait dengan pemrograman kita di sistem operasi Windows 32-bit dan menetapkan tampilan waktu dan ruang yang benar di WIN32. Saya berharap setelah membaca bab ini, kita dapat memiliki pemahaman yang lebih dalam tentang program, proses dan thread, memahami prinsip-prinsip file yang dapat dieksekusi, pustaka tautan dinamis dan paket runtime, dan melihat dengan jelas kebenaran tentang data global, data lokal, dan parameter di memori. .
Bagian 1 Memahami Prosesnya
Karena alasan historis, Windows berasal dari DOS. Di era DOS, kita selalu hanya mempunyai konsep program, bukan konsep proses. Pada saat itu, hanya sistem operasi biasa, seperti UNIX dan VMS, yang memiliki konsep proses, dan multi-proses berarti komputer mini, terminal, dan banyak pengguna, yang juga berarti uang. Seringkali, saya hanya dapat menggunakan mikrokomputer dan sistem DOS yang relatif murah. Saya baru mulai mengenal proses dan komputer mini ketika saya mempelajari sistem operasi.
Itu hanya setelah Windows 3. Dahulu, pada DOS, hanya satu program yang dapat dijalankan pada waktu yang sama, namun pada Windows, beberapa program dapat dijalankan pada waktu yang bersamaan. Saat menjalankan program di DOS, program yang sama tidak dapat dijalankan pada waktu yang sama, tetapi di Windows, lebih dari dua salinan program yang sama dapat dijalankan pada waktu yang sama, dan setiap salinan program yang berjalan adalah sebuah proses. Lebih tepatnya, setiap menjalankan program apa pun menghasilkan tugas, dan setiap tugas adalah sebuah proses.
Ketika program dan proses dipahami bersama, kata program dapat dianggap merujuk pada hal-hal statis. Program tipikal adalah kode statis dan data yang terdiri dari file EXE atau file EXE ditambah beberapa file DLL. Suatu proses adalah dijalankannya suatu program, yaitu kode dan data yang berubah secara dinamis yang berjalan secara dinamis di memori. Ketika program statis diperlukan untuk dijalankan, sistem operasi akan menyediakan ruang memori tertentu untuk operasi ini, mentransfer kode program dan data statis ke dalam ruang memori ini, dan memposisikan ulang serta memetakan kode program dan data di ruang ini dieksekusi di dalam, sehingga menciptakan proses yang dinamis.
Dua salinan dari program yang sama yang berjalan pada waktu yang sama berarti terdapat dua ruang proses dalam memori sistem, namun fungsi programnya sama, namun berada dalam keadaan yang berubah secara dinamis berbeda.
Dilihat dari waktu berjalannya proses, setiap proses dijalankan pada waktu yang sama. Istilah profesionalnya disebut eksekusi paralel atau eksekusi bersamaan. Tapi ini terutama perasaan dangkal yang diberikan sistem operasi kepada kita. Faktanya, setiap proses dijalankan dengan cara berbagi waktu, yaitu setiap proses secara bergiliran menggunakan waktu CPU untuk menjalankan instruksi program dari proses tersebut. Untuk CPU, hanya instruksi dari satu proses yang dijalankan pada waktu yang sama. Sistem operasi adalah manipulator di balik pengoperasian proses yang dijadwalkan. Sistem operasi secara konstan menyimpan dan mengubah status terkini dari setiap proses yang dijalankan di CPU, sehingga setiap proses yang dijadwalkan dianggap berjalan sepenuhnya dan terus menerus. Karena penjadwalan proses pembagian waktu sangat cepat, hal ini memberi kita kesan bahwa semua proses berjalan pada waktu yang sama. Faktanya, operasi simultan yang sebenarnya hanya mungkin dilakukan di lingkungan perangkat keras multi-CPU. Ketika kita berbicara tentang thread nanti, kita akan menemukan bahwa thread adalah yang benar-benar mendorong proses, dan yang lebih penting, thread menyediakan ruang proses.
Dalam hal ruang yang ditempati oleh proses, setiap ruang proses relatif independen, dan setiap proses berjalan dalam ruang independennya masing-masing. Suatu program mencakup ruang kode dan ruang data. Baik kode maupun data menempati ruang proses. Windows mengalokasikan memori sebenarnya untuk ruang data yang diperlukan oleh setiap proses, dan umumnya menggunakan metode berbagi untuk ruang kode, memetakan satu kode program ke beberapa proses program. Artinya jika suatu program mempunyai 100K kode dan memerlukan 100K ruang data, yang berarti dibutuhkan total 200K ruang proses, sistem operasi akan mengalokasikan 200K ruang proses saat pertama kali program dijalankan, dan 200K ruang proses. ruang akan dialokasikan saat program dijalankan untuk kedua kalinya. Ketika suatu proses dimulai, sistem operasi hanya mengalokasikan 100K ruang data, sedangkan ruang kode berbagi ruang dengan proses sebelumnya.
Di atas adalah tampilan waktu dan ruang dasar dari proses di sistem operasi Windows. Faktanya, terdapat perbedaan besar dalam tampilan waktu dan ruang dari proses antara sistem operasi Windows 16-bit dan 32-bit.
Dari segi waktu, proses manajemen sistem operasi Windows 16-bit, seperti Windows 3.x, sebenarnya hanya sistem operasi manajemen multi-tugas. Selain itu, penjadwalan tugas sistem operasi bersifat pasif. Jika tugas tidak berhenti memproses pesan, sistem operasi harus menunggu. Karena kelemahan dalam manajemen proses sistem Windows 16-bit, ketika suatu proses sedang berjalan, itu sepenuhnya menghabiskan sumber daya CPU. Pada masa itu, agar Windows 16-bit mempunyai kesempatan untuk menjadwalkan tugas-tugas lain, Microsoft memuji para pengembang aplikasi Windows karena menjadi pemrogram yang berwawasan luas, sehingga mereka bersedia menulis beberapa baris kode lagi sebagai hadiah kepada para pengembang. sistem operasi. Sebaliknya, sistem operasi WIN32, seperti Windows 95 dan NT, memiliki kemampuan sistem operasi multi-proses dan multi-tasking yang nyata. Proses di WIN32 sepenuhnya dijadwalkan oleh sistem operasi. Setelah waktu proses yang berjalan berakhir, sistem operasi akan secara aktif beralih ke proses berikutnya terlepas dari apakah proses tersebut masih memproses data. Sebenarnya, sistem operasi Windows 16-bit tidak dapat dianggap sebagai sistem operasi yang lengkap, tetapi sistem operasi Win32 32-bit adalah sistem operasi yang sebenarnya. Tentu saja, Microsoft tidak akan mengatakan bahwa Win32 menebus kekurangan jendela 16-bit, tetapi mengklaim bahwa Win32 mengimplementasikan teknologi canggih yang disebut "preemptive multitasking", yang merupakan metode komersial.
Dari perspektif ruang, meskipun ruang proses dalam sistem operasi Windows 16-bit relatif independen, proses dapat dengan mudah mengakses ruang data masing-masing. Karena proses ini sebenarnya adalah segmen data yang berbeda dalam ruang fisik yang sama, dan operasi alamat yang tidak tepat dapat dengan mudah menyebabkan pembacaan dan penulisan ruang yang salah, dan menghancurkan sistem operasi. Namun, dalam sistem operasi Win32, setiap ruang proses sepenuhnya independen. Win32 memberikan setiap proses dengan ruang alamat virtual dan berkelanjutan hingga 4G. Ruang alamat kontinu yang disebut berarti bahwa setiap proses memiliki ruang alamat dari $ 00000000 hingga $ FFFFFFFFF, daripada ruang tersegmentasi dari jendela 16-bit. Di Win32, Anda tidak perlu khawatir tentang operasi membaca dan menulis secara tidak sengaja mempengaruhi data di ruang proses lain, dan Anda tidak perlu khawatir tentang proses lain yang akan melecehkan pekerjaan Anda. Pada saat yang sama, ruang virtual 4G berkelanjutan yang disediakan oleh Win32 untuk proses Anda adalah memori fisik yang dipetakan kepada Anda oleh sistem operasi dengan dukungan perangkat keras. memori fisik.
Bagian 2 Proses Ruang
Ketika kami menggunakan Delphi untuk menulis aplikasi Win32, kami jarang peduli dengan dunia internal proses saat berjalan. Karena Win32 menyediakan 4G ruang proses virtual kontinu untuk proses kami, mungkin aplikasi terbesar di dunia saat ini hanya menggunakan sebagian darinya. Tampaknya ruang proses tidak terbatas, tetapi ruang proses 4G adalah virtual, dan memori aktual mesin Anda mungkin jauh dari ini. Meskipun proses ini memiliki ruang yang begitu luas, beberapa program algoritma yang kompleks masih tidak dapat berjalan karena tumpukan overflow, terutama program yang mengandung sejumlah besar algoritma rekursif.
Oleh karena itu, pemahaman mendalam tentang struktur ruang proses 4G, hubungannya dengan memori fisik, dll. Akan membantu kita memahami dunia ruang-waktu Win32 dengan lebih jelas, sehingga kita dapat menggunakan metode yang benar dalam pekerjaan pengembangan aktual Pandangan dunia dan metodologi untuk menyelesaikan berbagai masalah sulit.
Selanjutnya, kami akan menggunakan eksperimen sederhana untuk memahami dunia internal ruang proses Win32. Ini mungkin memerlukan beberapa pengetahuan tentang register piala dan bahasa perakitan, tetapi saya mencoba menjelaskannya dalam bahasa sederhana.
Ketika Delphi dimulai, proyek Project1 akan dihasilkan secara otomatis, dan kami akan memulainya. Tetapkan breakpoint di mana saja dalam program asli Project1.dpr, misalnya, menetapkan breakpoint pada kalimat awal. Kemudian jalankan program dan secara otomatis akan berhenti ketika mencapai breakpoint. Pada saat ini, kita dapat membuka jendela CPU di alat debugging untuk mengamati struktur internal ruang proses.
EIP register pointer instruksi saat ini dihentikan pada $ 0043E4B8. Proses Ruang, yang menempati $ 00000000 untuk ruang alamat yang cantik untuk $ ffffffff.
Di kotak perintah di jendela CPU, Anda dapat melihat isi ruang proses. Saat melihat konten ruang kurang dari $ 00400000, Anda akan menemukan serangkaian tanda tanya "????" Muncul dalam konten kurang dari $ 00400000. Jika Anda melihat nilai heksadesimal dari hinstance variabel global saat ini, Anda akan menemukan bahwa itu juga $ 00400000. Meskipun Hinstance mencerminkan pegangan instance proses, pada kenyataannya, itu adalah nilai alamat awal ketika program dimuat ke dalam memori, juga di jendela 16-bit. Oleh karena itu, kita dapat berpikir bahwa program proses dimuat mulai dari $ 00400000, yaitu ruang mulai dari 4m di ruang virtual 4G adalah ruang di mana program dimuat.
Dari $ 00400000 dan seterusnya dan sebelum $ 0044d000, ini terutama ruang alamat kode program dan data global. Di kotak tumpukan di jendela CPU, Anda dapat melihat alamat tumpukan saat ini. Demikian pula, Anda akan menemukan bahwa ruang alamat tumpukan saat ini dari $ 0067b000 hingga $ 00680000, dengan panjang $ 5.000. Faktanya, ukuran ruang tumpukan minimum dari proses ini adalah $ 5000, yang diperoleh berdasarkan nilai ukuran tumpukan min yang ditetapkan di halaman Linker ProjectOptions saat menyusun program Delphi, ditambah $ 1000. Tumpukan tumbuh dari alamat high-end ke bawah. ruang proses. Saat menyusun program Delphi, Anda dapat mengontrol ruang tumpukan maksimum yang dapat ditingkatkan dengan menetapkan nilai ukuran tumpukan maks di halaman tautan di ProjectOptions. Terutama dalam program yang mengandung hubungan panggilan subrutin yang dalam atau menggunakan algoritma rekursif, nilai ukuran tumpukan maks harus diatur secara wajar. Karena memanggil subrutin membutuhkan ruang tumpukan, dan setelah tumpukan habis, sistem akan melempar kesalahan "stack overflow".
Tampaknya ruang proses setelah ruang tumpukan harus menjadi ruang kosong. Bahkan, ini bukan masalahnya. Tampaknya prosesnya benar -benar hanya dapat memiliki ruang 2G. Faktanya, ruang yang benar -benar dapat dimiliki oleh suatu proses bahkan bukan 2G, karena ruang 4m dari $ 00000000 hingga $ 00400000 juga merupakan area terbatas.
Tapi apa pun yang terjadi, alamat yang dapat digunakan oleh proses kami masih sangat luas. Terutama setelah ruang tumpukan dan antara $ 80.000.000, itu adalah medan perang utama dari ruang proses. Ruang memori yang dialokasikan oleh proses dari sistem akan dipetakan ke ruang ini, pustaka tautan dinamis yang dimuat oleh proses akan dipetakan ke ruang ini, ruang tumpukan utas utas baru juga akan dipetakan ke ruang ini, hampir semua, hampir semua Operasi yang melibatkan alokasi memori semua akan dipetakan ke ruang ini. Harap dicatat bahwa pemetaan yang disebutkan di sini berarti korespondensi antara memori aktual dan ruang virtual ini. ???? ".