حول تخصيص ذاكرة الكائن وإعادة تدويرها
لا أعرف إذا كان لدى أي شخص أي أفكار حول وضع سجل dl هنا. إذا لم يكن الأمر كذلك، فكر في الأمر فقط. في الواقع، قبل الكود التالي (1)، يوجد مثل هذا السطر من الكود MOV dl، 1، فلماذا يكون الأمر هكذا؟ السبب ليس بسيطًا جدًا، إعادة استخدام الكود. فيما يتعلق باستخدام سجل dl هنا، هناك مقدمة في مساعدة دلفي. تحلى بالصبر وابحث عنه بنفسك، إذا وجدته، فستكون محترفًا. هذا هو التعلم، لا، تعلم الصيد، وليس طلب السمك. قال بورلاند: "أستخدم سجل dl لتخزين العلم. إذا كانت القيمة 1، فسوف أقوم بإنشاء الكائن. وإلا فلن أقوم بإنشاء الكائن إذا كنت غامضًا بعض الشيء، فكر في الأمر مرة أخرى." مرة أخرى. إذا لم تفتح عينيك بعد، فألق نظرة على الكود التالي (2)، لا تقل أنك لم تجده، السعال، ما الذي يحدث، ما زلت أتحدث هراء، أعدك بعدم قول ذلك مرة أخرى.
{الكود (1)
اختبار دل، دل
جي زي + 08 دولار
أضف esp، - 10 دولارات
اتصل بـClassCreate }
{///الكود (2)
PROcedure Tapplication.CreateForm(InstanceClass: TComponentClass; var Reference);
فار
المثيل: TComponent؛
يبدأ
//////// المثيل := TComponent(InstanceClass.NewInstance);
TComponent(Reference) := مثيل;
يحاول
//////// Instance.Create(Self);
يستثني
TComponent(Reference) := nil;
يرفع؛
نهاية؛
إذا (FMainForm = nil) و (Instance is TForm) إذن
يبدأ
TForm(Instance).HandleNeeded;
FMMainForm := TForm(Instance);
نهاية؛
نهاية؛
}
في هذه الحالة، أي أن دلفي تستدعي الكود (1) عندما يتم استدعاء مثيل الفئة التي تم إنشاؤها لأول مرة، ثم، إذا احتاج أي شخص إلى استدعاء طريقة الإنشاء، فأنا، لا، إنه المترجم، فقط مثل هذا MOV دل، 0، بحيث تنتقل تعليمات القفز للحكم 0 في الكود (1) إلى المكان الذي يجب أن تذهب إليه (لماذا تتحدث هراء مرة أخرى؟ أعدك بذلك في المرة الأخيرة.) في الواقع، طريقة الإنشاء هنا هي مجرد طريقة الطريقة العادية، و، يجب أن تلاحظ أيضًا أن الاستدعاء الأول لطريقة الإنشاء أو طريقة NewInstance هو الفئة التي ترسل هذه الرسالة (لاحظ أن هذه الرسالة ليست رسالة Windows، هذه الرسالة ليست الرسالة الأخرى، هاها، هذا هراء مرة أخرى، إنها حقًا المرة الأخيرة، هذا صحيح. إذا لم تفهم الرسالة هنا، فيرجى تعلم المعرفة الموجهة للكائنات والنمذجة بعناية) والاتصال تم إنشاء طريقة الإنشاء لاحقًا، وInstance.Create(Self); فكر في الأمر، بالطبع تغيرت قيمة سجل dl.
حسنًا، ليس لدي الكثير من الوقت، أخيرًا، أود أن أضيف ذلك فيما يتعلق بالعلم (طريقة الترجمة التايوانية، أعتقد أن هذه الكلمة جيدة، وأقترح عليك استخدامها أيضًا لتوفير الكثير من المتاعب لاحقًا) و تعليمات استخدام سجل dl هذا، يجب أن يقال أنه لن تكون هناك أي تغييرات. إذا فكرت في الأمر بعناية، لم تتغير دلفي من 1 إلى 6. وبالمناسبة، فإنه يثبت أيضًا أن مصمم Delphi HB هو مصمم. بطبيعة الحال، لا أستطيع المقارنة. هاها، ها نحن نعود مرة أخرى، حسنًا، سأتوقف عن الحديث. أوه، أخيرًا، اسمحوا لي أن أقول إن طريقة TObject.Create ليست بأي حال من الأحوال طريقة فارغة، تذكر، ثم فكر في الأمر.
حسنًا، الأشياء الأخرى، يرجى الذهاب ورؤيتها شخصيًا، وفي هذه الحالة سوف تكسب الكثير.
"اخرج من هنا، أريد أن أرى ذلك وأفكر فيه، ولا أريد هراءك!" كان هناك من يضحك! :)
الوداع
عندما يقوم المترجم بتخصيص ذاكرة لكائن ما، فإن الدعم الذي يقدمه هو إدراج هذه الأسطر من كود التجميع قبل استدعاء المنشئ:
اختبار دل، دل
جي زي + 08 دولار
أضف esp، - 10 دولارات
اتصل بـClassCreate // انتبه إلى هذا السطر من التعليمات البرمجية
يستدعي السطر الأخير من الكود أعلاه الدالة _ClassCreate في السطر 8949 من ملف system.pas (الخاضع لـ Delphi 6). تقوم هذه الدالة بتخصيص الذاكرة المناسبة لكل كائن على وجه التحديد. بعد اكتمال تخصيص الذاكرة، يتم استدعاء منشئ الفئة لتهيئة أعضاء البيانات. بعد ذلك، سيقوم المترجم بإدراج الأسطر التالية من كود التجميع:
اختبار دل، دل
جيز +$0f
اتصل بـAfterConstruction
البوب dWord ptr fs:[00000000 دولار]
أضف esp، $0c
المهمة الرئيسية هي استدعاء AfterConstruction لكل مثيل كائن. هذا الاستدعاء ليس له أي فائدة في دلفي. وجوده محجوز لـ C++ Builder.
وبالمثل، عند تدمير كائن ما، يجب أولاً استدعاء مدمر الفئة لتحرير الموارد التي يطلبها الكائن. بعد ذلك، يتم إعادة تدوير مساحة الذاكرة التي يشغلها الكائن نفسه. يكتمل هذا العمل عن طريق قيام المترجم بإدخال رمز التجميع التالي بعد استدعاء المدمر:
اتصل بـBeforeDestruction
اختبار دل، دل
سعر +05 دولار
اتصل بـClassDestroy
يتوافق العمل الذي يتم تنفيذه بواسطة هذه الرموز مع ما يتم تنفيذه عند إنشاء الكائن وتخصيص الذاكرة، وبشكل أساسي استدعاء وظيفة _ClassDestroy على السطر 8997 في system.pas.
البناء والمدمر
لتعريف مُنشئ، استخدم الكلمة الأساسية للمنشئ وفقًا للاتفاقية، اسم المُنشئ هو إنشاء (بالطبع يمكن استخدام أسماء أخرى، لكن هذا ليس تصميمًا جيدًا بأي حال من الأحوال!). يحب:
يكتب
TMyFamily = class // الفصل المحدد لعائلتك
خاص
FMyFatherName: سلسلة // اسم والدك
FMyMotherName: سلسلة // اسم والدتك
… // أفراد عائلتك الآخرين
عام
إنشاء المُنشئ (strFatherName، strMotherName : String)؛
…… // طرق أخرى
نهاية؛
قد تتساءل، إذا لم أقدم مُنشئًا لفصلي، فهل يمكن إنشاء كائناته؟ الجواب هو: نعم. لقد تم ذكر السبب من قبل، حيث يتم إكمال تخصيص الذاكرة التي يشغلها الكائن نفسه بواسطة المترجم. وبما أن جميع الفئات في Object Pascal (باستثناء فئة TObject نفسها) مشتقة من فئة TObject، فسيقوم المترجم باستدعاء مُنشئ TObject.Create()، لكن هذه الوظيفة هي وظيفة فارغة، ولن تؤثر على فئة TMyFamily عند تهيئة أعضاء البيانات (FMyFatherName، FMyMotherName)، سيتم مسحهم تلقائيًا إلى سلاسل فارغة (أي '')، لأن TObject.Create() لا يعرف والدك أو والدتك على الإطلاق!
عند إنشاء كائن، يتم استدعاء المنشئ مباشرة، بالشكل التالي:
MyFamilyObject := TMyFamily.Create('Zhang', 'Li');
استخدم الكلمة الأساسية Destructor لتعريف أداة التدمير حسب الاصطلاح، يُطلق على أداة التدمير اسم Destroy. يحب:
يكتب
TMyClass = class
عام
تجاوز المدمر () ؛
نهاية؛
السبب وراء إضافة بيان التجاوز في نهاية إعلان المدمر هو التأكد من إمكانية تدمير الكائن بشكل صحيح في حالة تعدد الأشكال (ستتم مناقشة تعدد الأشكال بالتفصيل في القسم 2.4). إذا لم تقم بإضافة الكلمة الأساسية للتجاوز، فسيقدم المترجم تحذيرًا مشابهًا لـ "الطريقة 'Destroy' تخفي الطريقة الافتراضية للنوع الأساسي 'TObject'". يعني التحذير أن التدمير الذي حددته يخفي الطريقة الافتراضية TObject.Destroy() للفئة الأساسية. في هذه الحالة، لا يمكن إتلاف الكائن بشكل صحيح في المواقف متعددة الأشكال.
ملاحظة: يجب الإعلان عن المدمرات ببيان تجاوز.
وبالمثل، إذا لم تكن هناك موارد خاصة تحتاج إلى إصدارها في فصلك الدراسي، فلن تحتاج إلى تحديد أداة إتلاف. ومع ذلك، عند تدمير كائن، يجب عليك استدعاء الأسلوب Free() الخاص بالكائن بدلاً من استدعاء Destroy() مباشرة.
MyFamilyObject.Free();
وذلك لأن الأسلوب Free() سيحدد ما إذا كان الكائن نفسه صفراً، وإذا لم يكن صفراً، فسيتم استدعاء Destroy() للكائن لزيادة الأمان. والآن بعد أن أصبحت هناك طرق أكثر أمانًا للقيام بذلك، فمن المؤكد أنه لا يوجد سبب لعدم القيام بذلك.
ملاحظة: لا تستدعي Destroy() مباشرة على كائن ما، بل تستدعي Free() بدلًا من ذلك.
يمكن أن نستنتج من هذا أنه في Object Pascal ما عليك سوى الاهتمام بتخصيص وإطلاق الموارد التي يطبقها الكائن، ولا يتعين عليك الاهتمام بالمساحة التي يشغلها الكائن نفسه!