Kodax

Nested و Local Classes — OOP في C++

الأصناف المتداخلة والمحلية

الصنف المتداخل (Nested Class)

صنف معرّف داخل صنف آخر. الاستخدام الأهم: إخفاء تفاصيل التنفيذ. عقدة القائمة المرتبطة لا معنى لها خارج القائمة:

#include <iostream>
#include <memory>
using namespace std;

class IntList {
    struct Node {                        // private: لا أحد خارج IntList يراه
        int value;
        unique_ptr<Node> next;
        explicit Node(int v) : value(v) {}
    };
    unique_ptr<Node> head;
    size_t count = 0;
public:
    void pushFront(int v) {
        auto n = make_unique<Node>(v);
        n->next = move(head);
        head = move(n);
        ++count;
    }
    void print() const {
        for (const Node* p = head.get(); p; p = p->next.get()) cout << p->value << ' ';
        cout << '\n';
    }
    size_t size() const { return count; }
};

int main() {
    IntList list;
    list.pushFront(3); list.pushFront(2); list.pushFront(1);
    list.print();                  // 1 2 3
    // IntList::Node n(5);         ← خطأ: Node خاص
}

قواعد الوصول

- الصنف المتداخل عضو في الصنف الخارجي، فيصل إلى أعضائه الخاصة (منذ C++11) — لكنه يحتاج كائناً منه، لأنه لا يملك this خاصاً بالخارجي.

- الصنف الخارجي لا يصل إلى الأعضاء الخاصة للمتداخل (لذلك جعلنا Node بنية struct بأعضاء public؛ فهي مخفية أصلاً لأنها private داخل IntList).

- إذا كان المتداخل public، يُستخدم من الخارج بالاسم الكامل: Outer::Inner.

أنواع متداخلة عامة

مكتبة STL تستخدم هذا كثيراً: vector<int>::iterator، map<K,V>::value_type. يمكنك فعل المثل:

class Order {
public:
    enum class Status { Pending, Paid, Shipped };    // نوع متداخل عام
    void setStatus(Status s) { status = s; }
    Status getStatus() const { return status; }
private:
    Status status = Status::Pending;
};
// Order o; o.setStatus(Order::Status::Paid);

الصنف المحلي (Local Class)

صنف معرّف داخل دالة، مرئي فيها فقط. قيوده: لا أعضاء static بيانات، ولا يمكن أن يكون قالباً. كان يُستخدم لكائنات دالة صغيرة، أما اليوم فالـ lambda تؤدي الغرض بشكل أوضح:

#include <algorithm>
#include <vector>
using namespace std;

void sortDesc(vector<int>& v) {
    struct Greater { bool operator()(int a, int b) const { return a > b; } };   // صنف محلي (أسلوب قديم)
    sort(v.begin(), v.end(), Greater{});
    sort(v.begin(), v.end(), [](int a, int b) { return a > b; });              // نفس الشيء بـ lambda
}

متى تستخدم ماذا؟

| الحالة | الأداة |

|---|---|

| تفصيل تنفيذ يخص صنفاً واحداً (Node، Iterator) | صنف متداخل private |

| نوع مرتبط بالصنف يحتاجه المستخدم (Status) | نوع متداخل public |

| منطق صغير داخل دالة | lambda |

تمرين

أضف إلى IntList صنفاً متداخلاً عاماً Stats (min, max, sum) ودالة Stats stats() const تحسبها في مرور واحد.

#include <iostream>
#include <vector>
#include <string>
using namespace std;

class LinkedList {
private:
    // Nested class - Node
    class Node {
    public:
        int data;
        Node* next;
        
        Node(int d) : data(d), next(nullptr) {}
    };
    
    Node* head;
    int size;

public:
    // Public nested class - Iterator
    class Iterator {
    private:
        Node* current;
    public:
        Iterator(Node* node) : current(node) {}
        
        int& operator*() { return current->data; }
        
        Iterator& operator++() {
            if (current) current = current->next;
            return *this;
        }
        
        bool operator!=(const Iterator& other) const {
            return current != other.current;
        }
    };
    
    LinkedList() : head(nullptr), size(0) {}
    
    ~LinkedList() {
        while (head) {
            Node* temp = head;
            head = head->next;
            delete temp;
        }
    }
    
    void push_front(int data) {
        Node* newNode = new Node(data);
        newNode->next = head;
        head = newNode;
        size++;
    }
    
    void push_back(int data) {
        Node* newNode = new Node(data);
        if (!head) {
            head = newNode;
        } else {
            Node* current = head;
            while (current->next) {
                current = current->next;
            }
            current->next = newNode;
        }
        size++;
    }
    
    int getSize() const { return size; }
    
    Iterator begin() { return Iterator(head); }
    Iterator end() { return Iterator(nullptr); }
};

// مثال آخر: Menu System
class Restaurant {
public:
    // Public nested class
    class MenuItem {
    private:
        string name;
        double price;
        string category;
    public:
        MenuItem(const string& n, double p, const string& c)
            : name(n), price(p), category(c) {}
        
        string getName() const { return name; }
        double getPrice() const { return price; }
        string getCategory() const { return category; }
        
        void display() const {
            cout << "  • " << name << " - $" << price << endl;
        }
    };

private:
    string name;
    vector<MenuItem> menu;

public:
    Restaurant(const string& n) : name(n) {}
    
    void addItem(const string& itemName, double price, const string& category) {
        menu.push_back(MenuItem(itemName, price, category));
    }
    
    void displayMenu() const {
        cout << "\n🍽️ قائمة " << name << endl;
        cout << string(30, '=') << endl;
        
        string currentCategory = "";
        for (const auto& item : menu) {
            if (item.getCategory() != currentCategory) {
                currentCategory = item.getCategory();
                cout << "\n" << currentCategory << ":" << endl;
            }
            item.display();
        }
    }
    
    double calculateTotal(const vector<int>& itemIndexes) const {
        double total = 0;
        for (int idx : itemIndexes) {
            if (idx >= 0 && idx < menu.size()) {
                total += menu[idx].getPrice();
            }
        }
        return total;
    }
};

int main() {
    // استخدام LinkedList مع Iterator
    cout << "=== LinkedList ===" << endl;
    LinkedList list;
    list.push_back(10);
    list.push_back(20);
    list.push_back(30);
    list.push_front(5);
    
    cout << "العناصر: ";
    for (LinkedList::Iterator it = list.begin(); it != list.end(); ++it) {
        cout << *it << " ";
    }
    cout << endl;
    
    // Range-based for (يعمل مع begin/end)
    cout << "باستخدام range-for: ";
    for (int x : list) {
        cout << x << " ";
    }
    cout << endl;
    
    // استخدام Restaurant
    cout << "\n=== Restaurant ===" << endl;
    Restaurant restaurant("البيت العربي");
    
    restaurant.addItem("حمص", 5.99, "المقبلات");
    restaurant.addItem("فتوش", 6.99, "المقبلات");
    restaurant.addItem("شاورما", 12.99, "الأطباق الرئيسية");
    restaurant.addItem("كباب", 15.99, "الأطباق الرئيسية");
    restaurant.addItem("كنافة", 7.99, "الحلويات");
    
    restaurant.displayMenu();
    
    // إنشاء MenuItem من الخارج
    Restaurant::MenuItem customItem("طبق خاص", 20.00, "خاص");
    cout << "\nطبق مخصص: " << customItem.getName() << endl;
    
    return 0;
}
اختبر فهمك