الرجوع للقائمة الرئيسية (Back to Home)

Lecture 3: Constructors & Destructors

المحاضرة الثالثة: البناء والهدم (Constructors & Destructors)

الشرح التفصيلي لجميع شرائح المحاضرة (Slide-by-Slide) مدعوم بشرح الأكواد سطراً بسطر (Line-by-Line Code Explanation)

Slide 4: مقدمة عن المُنشئ (Introduction to Constructors)

Slide 4

في المحاضرات اللي فاتت، عرفنا إن الـ Class هو مجرد قالب (Blueprint)، وإن الـ Object هو النسخة الحقيقية اللي بتاخد مساحة في الـ Memory.

السؤال هنا: إمتى وإزاي الـ Object ده بيتولد أو بيتخلق في الـ Memory؟ وإزاي بياخد قيم ابتدائية (Initial Values) لأول مرة؟

الإجابة هي الـ Constructor (المُنشئ أو الدالة البانية). الـ Constructor عبارة عن Special Member Function (دالة خاصة جداً) بيتم استدعاؤها (Called) بشكل تلقائي (Automatically) بمجرد ما حضرتك تكتب كود إنشاء الـ Object.

وظيفة الـ Constructor الأساسية هي تهيئة (Initialization) المتغيرات أو الداتا بتاعة الـ Object الجديد وإعطاؤه حياة فعلية في الذاكرة.

Slide 5: خصائص وقواعد الـ Constructor (Rules of Constructors)

Slide 5

الـ Constructor مش دالة عادية، ليه 3 قواعد أو شروط صارمة لازم تحفظهم زي اسمك (بييجوا دايماً في الـ MCQs):

  • 1. Same Name: اسم الـ Constructor لازم يكون نفس اسم الـ Class بالظبط (بنفس الحروف الـ Capital والـ Small).
  • 2. No Return Type: الـ Constructor ملوش أي نوع إرجاع، حتى ولا كلمة void. مبنكتبش قبله أي حاجة.
  • 3. Automatic Call: إنت كمبرمج مش بتنادي عليه بشكل صريح (You don't call it explicitly)، هو بيشتغل لوحده أوتوماتيك أول ما تعمل Object جديد.
  • 4. Access Modifier: دايماً وأبداً لازم يكون محطوط في الـ public section، لأن الـ Main function هي اللي بتستخدمه عشان تبني الـ Object.

Slide 6: النوع الأول - المُنشئ الافتراضي (Default Constructor)

Slide 6

أول وأبسط نوع هو الـ Default Constructor. ده الـ Constructor الغلبان اللي مبياخدش أي Parameters (أقواسه فاضية).

وظيفته إنه بيدي قيم افتراضية (Default values) ثابتة لكل الـ Objects اللي بتتعمل منه (مثلاً يخلي أي Employee جديد يبدأ بمرتب 0 واسم فاضي).

⚠️ ملاحظة هامة جداً (Compiler Default): لو إنت نسيت أو متعمدتش تكتب أي Constructor في الكلاس بتاعك، الكومبايلر (Compiler) مش هيسكت، وهيكريتلك هو Hidden Default Constructor من وراك (فاضي مبيعملش حاجة) عشان بس يقدر يخلق الـ Objects. بس لو إنت كتبت أي Constructor بأيدك (حتى لو بياخد parameters)، الكومبايلر هيرفع إيده ومش هيعملك الـ Default.

Slide 7: كود المُنشئ الافتراضي (Default Constructor Example)

Slide 7

تعالوا نشوف إزاي بنكتب الـ Default Constructor في كود الـ C++ الفعلي:

class Student { private: int id; float gpa; public: // Default Constructor Student() { id = 0; gpa = 0.0; cout << "Default Constructor Called!" << endl; } }; int main() { // Object Creation -> Automatically calls Student() Student s1; return 0; }

شرح الكود سطراً بسطر (Line-by-Line Analysis):

Quiz 1: Constructors Basics

1. Which of the following statements about C++ Constructors is FALSE?

2. What happens if a programmer does not define any constructor in their C++ class?

Slide 8: النوع الثاني - المُنشئ بالمعاملات (Parameterized Constructor)

Slide 8

المشكلة في الـ Default Constructor إنه بيخلي كل الـ Objects تطلع شبه بعضها بالظبط بنفس القيم الأولية (الكل يبدأ بـ id = 0). لكن في الحقيقة، أنا عايز لما أجيب موظف جديد أقوله "خد إنت اسمك أحمد ومرتبك كذا" وأنا بكريته على طول.

هنا بنستخدم النوع التاني وهو الـ Parameterized Constructor. ده مُنشئ بياخد مدخلات (Parameters/Arguments) وإحنا بنعمل الـ Object.

الطريقة دي بتوفر علينا سطور كود كتير وبنعمل إنشاء (Creation) وتهيئة (Initialization) في سطر واحد بس (One-Step process).

Slide 9: كود المُنشئ بالمعاملات (Parameterized Constructor Example)

Slide 9

إزاي نكتب الـ Parameterized Constructor ونستخدمه؟

class Student { private: int id; float gpa; public: // Parameterized Constructor Student(int i, float g) { id = i; gpa = g; } }; int main() { // Explicit call to Parameterized Constructor Student s1(101, 3.5); Student s2(102, 3.9); return 0; }

شرح الكود سطراً بسطر (Line-by-Line Analysis):

Slide 10: تعدد المُنشئات (Constructor Overloading)

Slide 10

مبدأ الـ Polymorphism اللي درسناه المحاضرة اللي فاتت بيظهر هنا بقوة في حاجة اسمها Constructor Overloading.

يعني إيه Overloading؟ يعني أقدر أعمل جوه نفس الـ Class أكتر من Constructor واحد!

إزاي الكومبايلر مش هيتلخبط وهم كلهم ليهم نفس الاسم (اسم الكلاس)؟ الكومبايلر ذكي وبيفرق بينهم عن طريق حاجة اسمها الـ Signature (التوقيع)، وهو عدد ونوع الـ Parameters اللي كل Constructor بياخدها.

فلو إنت بعت باراميترز وإنت بتعمل الـ Object هينادي الـ Parameterized، ولو مبعتتش حاجة خالص هينادي الـ Default.

Slide 11: كود الـ Overloading (Constructor Overloading Example)

Slide 11

التطبيق العملي إننا نجمع الـ Default والـ Parameterized في كلاس واحد:

class Rectangle { private: int length, width; public: // Constructor 1: Default Rectangle() { length = 1; width = 1; } // Constructor 2: Parameterized (1 Argument) Rectangle(int x) { length = x; width = x; // Makes a square } // Constructor 3: Parameterized (2 Arguments) Rectangle(int l, int w) { length = l; width = w; } }; int main() { Rectangle r1; // Calls Constructor 1 (1x1) Rectangle r2(5); // Calls Constructor 2 (5x5) Rectangle r3(4, 6); // Calls Constructor 3 (4x6) }
💡 نصيحة للمحترفين (Best Practice): دايماً عود نفسك أول ما تكتب كلاس وتكتب فيه Constructor بياخد Parameters (النوع التاني)، إنك لازم تكتب الـ Default Constructor الفاضي بإيدك (النوع الأول). ليه؟ لأننا قلنا إن الكومبايلر أول ما يلاقيك كتبت Constructor بيلغي الـ Default المجاني بتاعه. فلو حبيت بعدين تعمل Object فاضي (زي r1) البرنامج هيديك Error لأن الـ Default مبقاش موجود!

Slide 12: النوع الثالث - مُنشئ النسخ (Copy Constructor)

Slide 12

النوع التالت والأخير والمهم جداً هو الـ Copy Constructor (مُنشئ النسخ).

من اسمه، هو Constructor وظيفته إنه يعمل Object جديد بناءً على Object قديم موجود بالفعل. يعني كأنه بيعمل ماكينة تصوير (Photocopy) للـ Object الأولاني وياخد كل بياناته يحطها في الـ Object الجديد.

الـ Syntax بتاعه بيكون مميز، لأنه بياخد Reference (&) من Object تاني من نفس الكلاس كـ Parameter.

Slide 13: كود مُنشئ النسخ (Copy Constructor Example)

Slide 13

إزاي نبرمج مُنشئ النسخ خطوة بخطوة:

class Box { private: int size; public: // 1. Parameterized Constructor Box(int s) { size = s; } // 2. Copy Constructor Box(const Box &old_box) { size = old_box.size; } }; int main() { Box b1(10); // Calls Parameterized Constructor Box b2(b1); // Calls Copy Constructor! b2 is now a clone of b1 Box b3 = b1; // This ALSO calls the Copy Constructor! }

شرح الكود سطراً بسطر (Line-by-Line Analysis):

Quiz 2: Parameterized & Copy Constructors

1. In C++, Constructor Overloading means having multiple constructors in the same class. How does the compiler distinguish between them?

2. What is the standard parameter type for a Copy Constructor in a class named `Test`?

Slide 14: الهدم والإنهاء (Destructors)

Slide 14

زي ما كل بداية ليها نهاية، وكل Object بيتولد بالـ Constructor، لازم الـ Object ده يموت ويتمسح من الميموري (Memory) عشان نوفر مساحة.

العملية دي بيقوم بيها الـ Destructor (الهدّام أو المُدمر).

الـ Destructor هو Special Member Function برضه، بيشتغل أوتوماتيك بس مش في بداية حياة الـ Object، لأ! ده بيشتغل في نهاية حياة الـ Object (End of Lifetime) أو لما البرنامج يخلص (Goes out of scope).

Slide 15: خصائص الـ Destructor (Rules of Destructors)

Slide 15

قواعد الـ Destructor شبه قواعد الـ Constructor بس مع اختلافات جوهرية عشان هو بيمسح مش بيبني:

  • 1. Name with Tilde: اسمه بيكون نفس اسم الـ Class بالظبط، بس لازم يسبقه علامة الـ Tilde ~ (زي كده: ~Student()). دي اللي بتعرف الكومبايلر إنه Destructor.
  • 2. No Return Type: برضه ملوش أي نوع إرجاع (No return type).
  • 3. No Parameters (NO OVERLOADING!): الـ Destructor مستحيل ياخد Parameters أقواسه دايماً فاضية. وبما إنه مبياخدش Parameters، إذن مستحيل نعمل منه Overloading! الكلاس الواحد ملوش غير Destructor واحد فقططط.
  • 4. Automatic Call: بيشتغل لوحده لما المتغير (Object) ينتهي عمره الافتراضي (مثلاً الدالة اللي هو اتعمل جواها تخلص وقوسها } يتقفل).

Slide 16: كود الـ Destructor و دورة الحياة (Lifetime Example)

Slide 16

تعالوا نشوف كود بيجمع البناء والهدم مع بعض عشان نفهم الـ Flow بتاع البرنامج ماشي إزاي:

class Test { public: // Constructor Test() { cout << "Constructor Called!" << endl; } // Destructor (Notice the Tilde ~) ~Test() { cout << "Destructor Called!" << endl; } }; int main() { cout << "Main starts..." << endl; { // Start of an artificial Scope block Test t1; // Object created -> Constructor called cout << "Inside scope block" << endl; } // End of scope -> Object t1 dies -> Destructor called AUTOMATICALLY cout << "Main ends." << endl; return 0; }

تحليل المخرجات (Output Analysis):

  • الطباعة هتكون بالترتيب ده:
  • Main starts... (لأن البرنامج بيبدأ من فوق).
  • Constructor Called! (لأننا كريتنا t1 جوه القوس).
  • Inside scope block (سطر طباعة عادي).
  • Destructor Called! (أول ما القوس الداخلي } اتقفل، الـ Object t1 مبقاش ليه لازمة وهيموت، فالـ Destructor بيشتغل ينضف مكانه).
  • Main ends. (البرنامج بيكمل عادي).

Slide 17: ترتيب استدعاء الـ Constructors و الـ Destructors

Slide 17

سؤال امتحانات 100%: لو عملت أكتر من Object ورا بعض، مين هيتهد الأول؟

قاعدة ذهبية: الـ Destructors بتشتغل بعكس ترتيب الـ Constructors.

المبدأ ده اسمه LIFO (Last In, First Out) اللي دخل الآخر، هو اللي هيخرج (يتهد) الأول. بالظبط زي لما ترص كتب فوق بعضها (ده الـ Constructor)، ولما تيجي تشيلهم عشان تنضف الترابيزة، هتشيل الكتاب اللي فوق خالص الأول (الـ Destructor).

Slide 18: مثال على الترتيب العكسي (LIFO Order Example)

Slide 18

تعالوا نأكد على القاعدة دي بالكود:

int main() { Test obj1; // 1st created Test obj2; // 2nd created Test obj3; // 3rd created return 0; } // End of main() -> All objects go out of scope here

شرح الكود سطراً بسطر (Line-by-Line Analysis):

Slide 19: الكائنات العامة والمحلية (Global vs Local Objects)

Slide 19

هنا بنزود مستوى التعقيد في الترتيب (Level Up). عندنا كذا نوع من الـ Objects على حسب مكان تعريفها:

  • Global Objects: الكائنات العامة اللي بتتعرف بره الـ main() خالص. دي أول حاجة بتتولد في البرنامج (قبل الـ main ما تبدأ أساساً!)، وهي آخر حاجة بتتهد في البرنامج لأنها عايشة طول فترة الـ Run.
  • Local Objects: الكائنات المحلية اللي جوه دوال زي main()، دي بتتولد لما الكود يوصلها، وتموت لما الدالة بتاعتها تقفل.
  • Static Local Objects: الكائنات اللي بنكتب قبلها كلمة static. دي بتتولد مرة واحدة بس (مش كل شوية)، ومش بتتهد لما الدالة تقفل! بتفضل عايشة وتتهد في نهاية البرنامج خالص مع الـ Global.

Slide 20: مثال شامل على الترتيب (Comprehensive Order Example)

Slide 20

دي مسألة امتحان نموذجية جداً بتدمج الـ Global والـ Local مع بعض:

Test globalObj; // Global Object void myFunc() { Test localObj2; // Local to myFunc } int main() { Test localObj1; // Local to main myFunc(); return 0; }
  • الترتيب الصحيح للبناء (Constructors):
    1. globalObj (لأنها Global، بتتنفذ قبل الـ main).
    2. localObj1 (أول سطر في الـ main).
    3. localObj2 (لما الـ main ندهت على myFunc()).
  • الترتيب الصحيح للهدم (Destructors):
    1. localObj2 (أول ما myFunc() قفلت السكوب بتاعها، مات فوراً).
    2. localObj1 (لما الـ main() قفلت).
    3. globalObj (بعد ما البرنامج كله خلص).

Slide 21: الـ Destructors والميموري الديناميكية (Destructors and Dynamic Memory)

Slide 21

ممكن تسأل نفسك: ليه إحنا محتاجين الـ Destructor أصلاً؟ ما الكومبايلر بيمسح المتغيرات العادية لوحده في الآخر!

كلامك صح في المتغيرات العادية (زي int x). لكن الفايدة الوحيدة الحقيقية والأقوى للـ Destructor بتظهر لما تكون بتستخدم حاجة اسمها Dynamic Memory Allocation (حجز الذاكرة الديناميكي باستخدام Pointers و كلمة new).

في الـ Dynamic Memory، الكومبايلر مش بيمسح الميموري اللي إنت حجزتها بإيدك بكلمة new لما الـ Object يموت. الميموري بتفضل محجوزة على الفاضي وبتعمل كارثة اسمها Memory Leak (تسريب الذاكرة) واللي ممكن يعلق الجهاز كله!

الحل الوحيد هو إنك تيجي جوه الـ ~Destructor() وتكتب كلمة delete ptr; عشان تضمن إن أول ما الـ Object ينتهي، الميموري الديناميكية بتاعته تتنضف وتتحرر للسيستم تاني (Free Memory).

Slide 22: الخلاصة (Summary & Best Practices)

Slide 22

ملخص سريع (Quick Recap) لأهم النقاط في المحاضرة دي:

  • الـ Constructor بيبني ويهيء (Initialize)، اسمه نفس اسم الكلاس، ملوش Return، بيشتغل لوحده.
  • أنواع الـ Constructor: (Default فاضي)، (Parameterized بياخد مدخلات)، (Copy بينسخ Object كامل).
  • الـ Destructor بيهد وينضف الميموري (مهم جداً مع الـ Pointers)، اسمه قبله ~، ومفيش منه غير واحد بس لأنه مبيقبلش مدخلات.
  • ترتيب الهدم دايماً LIFO (Last In First Out) عكس ترتيب البناء.

Final Quiz: Destructors & Order

1. Which of the following is true about Destructors in C++?

2. If three local objects obj1, obj2, and obj3 are created in that specific order inside a block. What will be the order of their destruction when the block ends?

الملخص الشامل لأهم التريكات (Summary & Pro Tips)

سؤال مقالي متوقع للامتحان (Essay Question)

Question: Compare and contrast the three types of Constructors in C++ (Default, Parameterized, Copy). For each type, explain its purpose, syntax, and when the compiler automatically invokes it. Also, explain the role of the Destructor and the LIFO rule for destruction order.

🖥️ What is the output of the following code?

Q1:

class Demo { public: Demo() { cout << "Constructor "; } ~Demo() { cout << "Destructor "; } }; int main() { Demo d1, d2; }

Q2:

class Point { public: int x, y; Point(int a, int b) { x = a; y = b; } Point(const Point &p) { x = p.x + 1; y = p.y + 1; } }; int main() { Point p1(3, 5); Point p2 = p1; cout << p2.x << " " << p2.y << endl; }

✍️ Write a line of code for the following statements

Q1: Write a Default Constructor for a class called Student that initializes id to 0 and name to "Unknown".

Q2: Write a Parameterized Constructor for Student that takes int i and string n.

Q3: Write a Copy Constructor for class Student.

Q4: Write a Destructor for class Student.

🔍 Based on the following code, answer all the following questions

class Item { private: int id; float price; public: Item() { id = 0; price = 0.0; cout << "D "; } Item(int i, float p) { id = i; price = p; cout << "P "; } Item(const Item &obj) { id = obj.id; price = obj.price; cout << "C "; } ~Item() { cout << "X "; } }; int main() { Item a; Item b(1, 9.99); Item c = b; }

a) What is the full output of this program?

b) Which constructor is called for object c? Why?

c) What happens if we remove the Default Constructor and keep only the Parameterized one?