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

Comprehensive Final Exam

🏆 المراجعة النهائية الشاملة 🏆

تشمل أهم الأفكار المتوقعة في الامتحان من المحاضرة 1 إلى المحاضرة 10

إعداد المهندس: Ahmed Amir Ahmed

القسم الأول: توقع المخرجات (What is the Output?) 🖥️

Q1. Pointers & References (Lectures 4 & 5)

#include <iostream>
using namespace std;

void modify(int* p, int& r) {
    *p = 10;
    r = 20;
}

int main() {
    int a = 5;
    int b = 5;
    modify(&a, b);
    cout << a << " " << b << endl;
    return 0;
}
👁️ إظهار الإجابة والتفسير
Output:
10 20

Explanation:

The function takes a pointer to `a` and a reference to `b`. Dereferencing `p` changes `a`'s actual value in memory to 10. Modifying `r` directly changes `b`'s value to 20 because it is passed by reference.

بالعامية: هنا إحنا باعتين المتغير الأول a كـ Pointer يعني بعتنا عنوانه في الميموري، فلما غيرنا *p اتغيرت القيمة الأصلية لـ 10. والمتغير التاني b مبعوت كـ Reference (يعني اسم دلع لنفس المكان في الميموري)، فلما غيرنا r لـ 20، اتغيرت b الأصلية لـ 20 بردو. فالطباعة هتكون 10 20.

Q2. Inheritance & Constructors (Lectures 6 & 7)

#include <iostream>
using namespace std;

class Base {
public:
    Base() { cout << "B "; }
    ~Base() { cout << "~B "; }
};

class Derived : public Base {
public:
    Derived() { cout << "D "; }
    ~Derived() { cout << "~D "; }
};

int main() {
    Derived obj;
    return 0;
}
👁️ إظهار الإجابة والتفسير
Output:
B D ~D ~B 

Explanation:

When a derived class object is created, the Base class constructor is called first, followed by the Derived class constructor. When the object goes out of scope, destructors are called in the exact reverse order: Derived first, then Base.

بالعامية: القاعدة بتقول: وأنت بتبني العمارة بتبني الأساس (Base) الأول وبعدين الدور اللي فوقه (Derived). لكن وأنت بتهد (Destructor)، بتهد من فوق لتحت. عشان كده الـ Constructor بتاع الـ Base اشتغل الأول وطبع B، بعده الـ Derived طبع D. ولما البرنامج خلص، الـ Destructor بتاع الـ Derived اشتغل الأول وطبع ~D، وبعده بتاع الـ Base طبع ~B.

Q3. Run-time Polymorphism (Lecture 8)

#include <iostream>
using namespace std;

class Animal {
public:
    virtual void sound() { cout << "Animal "; }
};

class Dog : public Animal {
public:
    void sound() { cout << "Bark "; }
};

int main() {
    Animal* ptr = new Dog();
    ptr->sound();
    delete ptr;
    return 0;
}
👁️ إظهار الإجابة والتفسير
Output:
Bark 

Explanation:

Because `sound()` is declared as `virtual` in the base class, C++ uses dynamic binding (run-time polymorphism). It looks at the actual object type (`Dog`) the pointer is pointing to, rather than the pointer's type (`Animal*`), and calls `Dog::sound()`.

بالعامية: طالما حطينا كلمة virtual قبل الفانكشن في الـ Base class، يبقى الـ C++ هيستنى وقت التشغيل (Run-time) عشان يشوف البوينتر ده بيشاور على أوبجيكت نوعه إيه بالظبط. هنا هو بيشاور على Dog، فهينفذ الفانكشن بتاعت الكلب ويطبع Bark، ومش هيبص لنوع البوينتر نفسه.

القسم الثاني: كتابة الأكواد (Write Code / Missing Parts) ✍️

Q4. Operator Overloading (Lectures 9 & 10)

Write the missing member function to overload the + operator for the Complex class so that c3 = c1 + c2 works correctly.

class Complex {
private:
    int real, imag;
public:
    Complex(int r = 0, int i = 0) : real(r), imag(i) {}
    
    // Write the operator+ function here
    _________________________________________
    _________________________________________
    _________________________________________
    _________________________________________
};
👁️ إظهار الإجابة والتفسير
Answer:
Complex operator+(const Complex& obj) {
    Complex temp;
    temp.real = real + obj.real;
    temp.imag = imag + obj.imag;
    return temp;
}

Explanation:

The overloaded operator takes a constant reference to another `Complex` object. It creates a temporary object, adds the calling object's properties with the passed object's properties, and returns the new temporary object.

بالعامية: دالة الـ Overloading هنا بترجع أوبجيكت جديد من نوع Complex. بتاخد أوبجيكت تاني كـ Parameter (اللي هو c2). جوه الدالة بنعمل أوبجيكت مؤقت temp، بنجمع فيه الحقيقي مع الحقيقي والتخيلي مع التخيلي، وفي الآخر بنـ return الـ temp ده عشان يتخزن في c3.

Q5. Pure Virtual Functions (Lecture 8)

Make the Shape class an Abstract Class by defining a pure virtual function called draw().

class Shape {
public:
    // Write the pure virtual function here
    _________________________________________
};
👁️ إظهار الإجابة والتفسير
Answer:
virtual void draw() = 0;

Explanation:

A pure virtual function is declared by assigning `0` to a virtual function. This makes the class abstract, meaning you cannot instantiate objects from it directly.

بالعامية: عشان نخلي الكلاس Abstract (يعني كلاس وهمي مقدرش أعمل منه أوبجيكت صريح)، بنعمل دالة virtual وبنساويها بـ 0. ده معناه إن أي كلاس هيورث من Shape غصب عنه لازم يكتب الكود بتاع دالة draw.

القسم الثالث: تحليل الأخطاء (Code Analysis & Bug Fixing) 🔍

Q6. Deep vs Shallow Copy (Lecture 5)

Identify the hidden bug in the following code and state how to fix it.

class String {
    char* data;
public:
    String(const char* str) {
        data = new char[strlen(str) + 1];
        strcpy(data, str);
    }
    ~String() { delete[] data; }
};

int main() {
    String s1("Hello");
    String s2 = s1; // What goes wrong here?
    return 0;
}
👁️ إظهار الإجابة والتفسير
The Bug:

Shallow Copy causing a Double Free Error. When `s2` is created, the default copy constructor copies the pointer `data` exactly. Both `s1.data` and `s2.data` point to the SAME memory address. When `main()` ends, the destructor is called twice for the same memory, crashing the program.

The Fix:

Implement a Custom Copy Constructor (Deep Copy):

String(const String& obj) {
    data = new char[strlen(obj.data) + 1];
    strcpy(data, obj.data);
}

Explanation:

بالعامية: المشكلة هنا خطيرة جداً! لما عملنا s2 = s1 الكومبايلر عمل Shallow Copy (نسخ سطحي)، يعني خلى البوينتر بتاع s2 يشاور على نفس المكان اللي بيشاور عليه s1. ولما البرنامج يخلص، هيمسح المكان ده مرتين (مرة لـ s1 ومرة لـ s2)، وده بيعمل Crash. الحل إننا نعمل Copy Constructor يعمل Deep Copy (نسخ عميق)، يعني يحجز مكان جديد في الميموري لـ s2 وينسخ فيه الحروف.

Q7. Constant Member Functions (Lecture 4)

Why will this code generate a compilation error?

class Point {
    int x, y;
public:
    Point(int x=0, int y=0) : x(x), y(y) {}
    void print() { cout << x << "," << y; }
};

void showPoint(const Point& p) {
    p.print(); // ERROR here
}
👁️ إظهار الإجابة والتفسير
The Bug:

Calling a non-const function (`print`) on a `const` object (`p`).

The Fix:

Mark the `print` function as constant by adding the `const` keyword at the end of its declaration:

void print() const { cout << x << "," << y; }

Explanation:

بالعامية: في دالة showPoint إحنا باعتين الأوبجيكت كـ const يعني بنقول للكومبايلر "ممنوع أي حد يعدل في الأوبجيكت ده". لكن دالة print مش مكتوب جنبها إنها const، فالكومبايلر بيخاف يخليك تناديها لإنها ممكن تكون بتعدل في الداتا. الحل إننا نحط كلمة const بعد دالة print عشان نطمن الكومبايلر إنها دالة للقراءة فقط (Read-only).

Q8. Static Members (Lecture 4)

#include <iostream>
using namespace std;

class Test {
    static int count;
public:
    Test() { count++; }
    static int getCount() { return count; }
};

int Test::count = 0;

int main() {
    Test t1, t2;
    {
        Test t3;
        cout << Test::getCount() << " ";
    }
    cout << t1.getCount() << endl;
    return 0;
}
👁️ إظهار الإجابة والتفسير
Output:
3 3

Explanation:

Static members are shared across all objects of the class. By the time `t3` is created, `count` is 3. When `t3` goes out of scope, the object is destroyed but the `count` is NOT decremented (since we didn't write `count--` in the destructor). Thus, `getCount()` still returns 3.

بالعامية: المتغير الـ Static بيبقى مشترك بين كل الأوبجيكتس مش خاص بواحد بس. عملنا 3 أوبجيكتس (t1, t2, t3) فالـ count زاد 3 مرات وبقى بـ 3، فطبعنا 3. الأوبجيكت التالت t3 اتمسح بعد القوس، بس إحنا معملناش Destructor يقلل الـ count ففضلت قيمته 3 زي ما هي لما طبعنا تاني.

Q9. Virtual Destructors (Lecture 8)

#include <iostream>
using namespace std;

class Base {
public:
    Base() { cout << "B() "; }
    ~Base() { cout << "~B() "; }
};

class Derived : public Base {
public:
    Derived() { cout << "D() "; }
    ~Derived() { cout << "~D() "; }
};

int main() {
    Base* ptr = new Derived();
    delete ptr;
    return 0;
}
👁️ إظهار الإجابة والتفسير
Output:
B() D() ~B()

Explanation:

This is a memory leak issue! Because the destructor in `Base` is NOT `virtual`, when we delete a `Base` pointer pointing to a `Derived` object, only the `Base` destructor is called. The `Derived` part of the object remains undeleted.

بالعامية: ركز هنا! إحنا عملنا بوينتر نوعه Base بيشاور على Derived. لما جينا نعمل delete، الكومبايلر بيبص على نوع البوينتر عشان مفيش كلمة virtual قبل الـ Destructor، فقام ماسح الجزء بتاع الأب بس وطبع ~B(). الجزء بتاع الابن فضل في الميموري وعملنا Memory Leak. عشان نصلح ده لازم نكتب virtual ~Base().

القسم الرابع: تصميم الـ UML (UML Diagrams) 📊

Q10. UML Class Diagram to Code (Lectures 2 & 3)

Write the C++ class declaration that matches the following UML diagram:

BankAccount
-------------------
- accountNumber: int
- balance: double
-------------------
+ BankAccount(accNum: int, bal: double)
+ deposit(amount: double): void
+ getBalance(): double
👁️ إظهار الإجابة والتفسير
Answer:
class BankAccount {
private:
    int accountNumber;
    double balance;
public:
    BankAccount(int accNum, double bal);
    void deposit(double amount);
    double getBalance();
};

Explanation:

In UML, the `-` sign means `private` and the `+` sign means `public`. The colon `:` is used to indicate the return type or variable type.

بالعامية: في الـ UML دايماً علامة الناقص - معناها إن الحاجة دي private، وعلامة الزائد + معناها public. وبنكتب اسم المتغير وبعدين نقطتين فوق بعض : وبعدين نوعه، ولما نيجي نحولها لكود بنقلب الترتيب ونخلي النوع الأول وبعده الاسم.

Q11. UML Relationships (Aggregation vs Composition)

What is the difference between the solid diamond and the hollow diamond in a UML class diagram?

👁️ إظهار الإجابة والتفسير
Answer:

Solid Diamond (Composition): "Part-of" relationship where the child object's lifecycle depends strictly on the parent. If the parent is destroyed, the child is destroyed.
Hollow Diamond (Aggregation): "Has-a" relationship where the child object can exist independently of the parent.


بالعامية:
- المعين المتظلل أسود (Solid Diamond) ده بيعبر عن الـ Composition يعني علاقة حياة أو موت. لو الكلاس الأب اتمسح، الابن هيتمسح معاه (زي الموبايل والبطارية الداخلية بتاعته).
- المعين الفاضي (Hollow Diamond) ده بيعبر عن الـ Aggregation يعني علاقة "عنده"، بس لو الأب اتمسح، الابن هيفضل موجود عادي (زي الطالب والمدرسة، لو المدرسة اتقفلت الطالب هيفضل موجود عادي).

🚀 انتقل إلى بنك الأسئلة الشامل (Mega Question Bank)