إعلان
دورة تطوير التطبيقات باستخدام لغة JavaScript في هذه الدورة ستتعلم لغة جافا سكريبت, استخدام مكتبة React.js, بناء API الموقع بواسطة Node.js, تطوير تطبيق جوال باستخدام React Native, و في نهاية الدورة ستتعلم تطوير تطبيق محادثة شبيه بتطبيق WhatsApp. تعلم الآن
دورة تطوير واجهات المستخدم في هذه الدورة ستتعلم لغة HTML و لغة CSS و لغة JavaScript. من ناحية التطبيق العملي ستتعلم طريقة بناء واجهة متجر إلكتروني مكون من ست صفحات, تحويل خمسة تصاميم PSD إلى صفحات ويب, بناء واجهة مستخدم تشبه موقع يوتيوب, بناء لوحة تحكم إحترافية. تعلم الآن
تطوير تطبيقات باستخدام لغة بايثون في هذه الدورة ستتعلم أساسيات البرمجة بلغة بايثون وصولاً إلى التعامل مع أشهر أطر العمل (Flask و Django) و ستتعلم كيف تبني متجر إلكتروني يمكن للمستخدمين البيع و الشراء من خلاله. تعلم الآن
دورة تطوير تطبيقات الويب باستخدام لغة PHP في هذه الدورة ستتعلم لغة PHP من الصفر, استخدام إطار العمل Laravel بشرح مفصّل و عملي, كيفية تطوير شبكة اجتماعية تشبه Instagram, بناء API لتطبيق جوال وفق أسلوب RESTful, تطوير موقع إعلانات مبوبة, تطوير نظام إدارة محتوى CMS كامل. تعلم الآن
دورة تطوير تطبيقات الويب باستخدام لغة Ruby في هذه الدورة ستتعلم البرمجة بلغة Ruby إنطلاقاً من أبسط المفاهيم وحتى بناء تطبيق حقيقي, إستخدام إطار العمل Ruby on Rails بشرح مفصّل و عملي, بناء تطبيق حقيقي عبارة عن شبكة اجتماعية تشبه تويتر, تطوير مجتمع الكتروني يشبه حسوب I/O. تعلم الآن
دورة علوم الحاسوب هذه الدورة معدة لتكون مدخل لعلوم الحاسوب و لغات البرمجة حيث ستتعرف فيها على أنظمة التشغيل و ستتعمق في نظام لينكس و في كيفية التعامل معه من خلال موجه الأوامر, بالإضافة إلى قواعد البيانات و أساسيات الشبكات و الخوادم و مبادئ الحماية والأمان في الويب. تعلم الآن

    C++ النطاقات ( Namespaces )

    مفهوم النطاق

    النطاق ( Namespace ) أسلوب مفيد جداً في تنظيم كود المشروع نتبعه لضمان عدم حدوث أي مشكلة سببها إستخدام نفس أسماء الأشياء التي تم تعريفها أكثر من مرة, أي لتجنب حدوث تضارب في الأسماء.

    إذا كنت أنت من يبني كل كود المشروع فإنك على الأغلب لن تواجه مشكلة سببها تضارب الأسماء لأنك أنت من تحدد أسماء الأشياء التي تقوم بتعريفها و بالتالي فإنك تعرف ما هي كل الأسماء التي وضعتها للمتغيرات و الدوال و الكلاسات في مشروعك. بينما حين تبدأ بتضمين مكتبات و ملفات فيها كود جاهز فهنا يصبح هناك احتمال كبير لحدوث تضارب بالأسماء.

    لاستخدام أي أسماء تريد في مشروعك بدون القلق ما إن كان تضمين أي كود جاهز فيه قد يسبب مشكلة تضارب الأسماء يمكنك من البداية وضع الكود الخاص فيك بداخل نطاق. عندها حتى إن كان كودك فيه نفس أسماء المتغيرات و الدوال و الكلاسات الموجودة في الكود الجاهز فإن هذا الأمر لن يسبب أي مشكلة بالنسبة للمترجم لأنه قادر على التفريق بينهم بكل سهولة.

    تضارب الأسماء

    تضارب الأسماء يعني محاولة تعريف نفس الشيء أكثر من مرة في نفس المكان.
    فيما يلي ستلاحظ أننا تعمدنا وضع أمثلة فيها مشكلة تضارب بالأسماء حتى تعرف ما هو المقصود بهذه المشكلة و كيف سنقوم لاحقاً بتجنب حدوثها.


    في المثال التالي قمنا حاولنا تعريف متغيرين إسمهما x في نفس الدالة مما سيؤدي لظهور مشكلة تضارب الأسماء عند التشغيل.
    ملاحظة: الخطأ سيحدث عند محاولة إعادة تعريف المتغير للمرة الثانية في نفس المكان.

    المثال الأول

    Main.cpp
    #include <iostream>
    
    int main()
    {
    	int x;
    	int x;   // إعادة تعريف متغير يملك نفس الإسم سيؤدي لحدوث تضارب في الأسماء
    	
        return 0;
    }
    		

    سيظهر الخطأ التالي عند التشغيل و الذي يعني أنه لا يمكن إعادة تعريف المتغير x كما حاولنا أن نفعل في السطر رقم 6.

    Line 6 | error: redeclaration of 'int x'


    في المثال التالي قمنا بإنشاء دالتين إسمهما printMsg() في نفس المكان مما سيؤدي لظهور مشكلة تضارب الأسماء عند التشغيل.
    ملاحظة: الخطأ سيحدث عند محاولة إعادة تعريف الدالة للمرة الثانية في نفس المكان.

    المثال الثاني

    Main.cpp
    #include <iostream>
    
    void printMsg()
    {
    
    }
    
    void printMsg()   // إعادة تعريف دالة تملك نفس الإسم و عدد الباراميترات سيؤدي لحدوث تضارب في الأسماء
    {
    
    }
    
    int main()
    {
        return 0;
    }
    		

    سيظهر الخطأ التالي عند التشغيل و الذي يعني أنه لا يمكن إعادة تعريف الدالة printMsg() كما حاولنا أن نفعل في السطر رقم 8.

    Line 8 | error: redeclaration of 'void printMsg()'

    الكلمة المفتاحية namespace

    تستخدم الكلمة namespace لتعريف نطاق جديد و وضع الكود فيه أو لتعريف إسم مختصر لنطاق موجود سابقاً.
    وضع الكود بداخل نطاق يتيح لك إعادة استخدام نفس أسماء الأشياء المعرّفة سابقاً في نفس المكان.


    الشكل العام لتعريف نطاق

    namespace namespace_name 
    {
       // هنا تضع أي كود تريد تعريفه بداخل النطاق
    }
    	

    • مكان الكلمة namespace_name تقوم بوضع الإسم الذي تريد وضعه للنطاق.
    • بين أقواس البداية و النهاية {...} يمكنك تعريف أي شيء تريده مثل متغيرات, دوال, كلاسات و حتى أنه يمكنك تعريف نطاقات داخلية.


    الشكل العام لتعريف نطاق بداخل نطاق

    يمكنك تعريف نطاق بداخل نطاق و هذا الأسلوب يسمى Nested Namespaces كالتالي.

    namespace outer_namspace_name 
    {
    	namespace inner_namspace_name 
    	{
    
    	}
    }
    	

    • مكان الكلمة outer_namespace_name تقوم بوضع إسم النطاق الخارجي و بداخل حدوده يمكنك كتابة أي كود تريده.
    • مكان الكلمة innner_namespace_name تقوم بوضع إسم النطاق الداخلي و بداخل حدوده يمكنك كتابة أي كود تريده أيضاً.


    في المثال التالي قمنا بتعريف متغير إسمه x بشكل مباشر في الملف و بجانبه قمنا بتعريف نطاق إسمه harmash يحتوي على متغير إسمه x أيضاً.

    المثال الأول

    Main.cpp
    #include <iostream>
    
    // x هنا قمنا بتعريف متغير عام إسمه
    int x;
    
    // أيضاً x يحتوي على متغير إسمه harmash هنا قمنا بتعريف نطاق إسمه
    namespace harmash
    {
        int x;
    }
    
    int main()
    {
    	// harmash الخاص بالنطاق x و القيم 2 في المتغير x هنا قمنا بوضع القيمة 1 في المتغير العام
        x = 1;
        harmash::x = 2;
    
    	// harmash الخاص بالنطاق x و المتغير x هنا قمنا بعرض قيمة المتغير العام
        std::cout << "x = " << x << std::endl;
        std::cout << "harmash::x = " << harmash::x;
    
        return 0;
    }
    		

    سنحصل على النتيجة التالية عند التشغيل.

    x = 1
    harmash::x = 2
    		


    في المثال التالي قمنا بتعريف دالة إسمه printMsg() بشكل مباشر في الملف و بجانبها قمنا بتعريف نطاق إسمه harmash يحتوي على دالة إسمها printMsg() أيضاً.

    المثال الثاني

    Main.cpp
    #include <iostream>
    
    // printMsg() هنا قمنا بتعريف دالة عامة إسمها
    void printMsg()
    {
    	std::cout << "printMsg is called \n";
    }
    
    // أيضاً printMsg() يحتوي على دالة إسمها harmash هنا قمنا بتعريف نطاق إسمه
    namespace harmash
    {
    	void printMsg()
    	{
    		std::cout << "harmash::printMsg is called \n";
    	}
    }
    
    int main()
    {
    	// harmash الخاصة بالنطاق printMsg() و الدالة printMsg() هنا قمنا باستدعاء الدالة العامة
        printMsg();
        harmash::printMsg();
    
        return 0;
    }
    		

    سنحصل على النتيجة التالية عند التشغيل.

    printMsg is called 
    harmash::printMsg is called 
    		


    في المثال التالي قمنا بتعريف نطاق إسمه outer يحتوي على دالة إسمها printMsg() و بداخله نطاق إسمه inner يحتوي على دالة إسمها printMsg() أيضاً.

    المثال الثالث

    Main.cpp
    #include <iostream>
    
    // printMsg() يحتوي على دالة إسمها outer هنا قمنا بتعريف نطاق إسمه
    namespace outer
    {
    	void printMsg()
    	{
    		std::cout << "outer::printMsg is called \n";
    	}
    	
    	// أيضاً printMsg() يحتوي على دالة إسمها inner هنا قمنا بتعريف نطاق إسمه
    	namespace inner
    	{
    		void printMsg()
    		{
    			std::cout << "inner::printMsg is called \n";
    		}
    	}
    }
    
    int main()
    {
    	// inner الخاصة بالنطاق printMsg() و الدالة outer الخاصة بالنطاق printMsg() هنا قمنا باستدعاء الدالة العامة
        outer::printMsg();
        outer::inner::printMsg();
    
        return 0;
    }
    		

    سنحصل على النتيجة التالية عند التشغيل.

    outer::printMsg is called
    inner::printMsg is called
    		

    الكلمة المفتاحية using

    تستخدم الكلمة using تستخدم لتضمين كل الكود الموجود بداخل النطاق الذي نحدده بعدها دفعة واحدة مما يجعلنا قادرين على التعامل مع الأشياء الموجودة فيه بدون الحاجة لذكر إسم النطاق في كل مرة.
    استخدام هذا الكلمة مفيد من ناحية أنه يقلل حجم الكود و لكن من ناحية أخرى يجبرك على تضمين كل الكود الموجود في النطاق و الذي قد لا تحتاجه أصلاً و قد يؤدي استخدام هذه الكلمة إلى حدوث مشكلة تضارب الأسماء أيضاً.


    معلومة تقنية

    في الدروس السابقة كنا نستخدم دائماً الكلمة using حين كنا نكتب using namespace std; بهدف استخدام الكود الموجود فيها بدون الحاجة لكتابة std:: في كل مرة, و لكن تذكر دائماً أنه يفضّل تجنب هذا الأمر لكي لا تقوم بتضمين أي كود لست بحاجة له و لضمان أن لا يحدث أي تضارب مع أسماء الأشياء التي تقوم بتعريفها.


    الشكل العام لتضمين كل كود النطاق

    using namespace namespace_name;
    	

    • مكان الكلمة namespace_name تقوم بوضع إسم النطاق الذي تريد تضمين كل الكود الموجود فيه.


    الشكل العام لتضمين كود نطاق موجود بداخل نطاق آخر

    using namespace parent_namespace_name::child_namespace_name;
    	

    • مكان الكلمة parent_namespace_name تقوم بوضع إسم النطاق الخارجي.
    • مكان الكلمة child_namespace_name تقوم بوضع إسم النطاق الداخلي الذي تريد كل الكود الموجود فيه.


    في المثال التالي قمنا بتعريف نطاق إسمه harmash يحتوي على دالتين إسمهما func1() و func2().
    بعدها قمنا بتضمين كل محتوى النطاق harmash حتى نتمكن من الوصول إلى الأشياء الموجودة فيه بشكل مباشر, أي بدون الحاجة لكتابة harmash:: في كل مرة.

    المثال الأول

    Main.cpp
    #include <iostream>
    
    // يحتوي على دالتين harmash هنا قمنا بتعريف نطاق إسمه
    namespace harmash
    {
        void func1()
    	{
    		std::cout << "func1 is called \n";
    	}
    	
        void func2()
    	{
    		std::cout << "func2 is called \n";
    	}
    }
    
    // harmash هنا قمنا بتضمين كل الكود الموجود في النطاق
    using namespace harmash;
    
    int main()
    {
    	// harmash اللتين قمنا بتضمينها من النطاق func2() و func1() هنا قمنا باستدعاء الدالتين
        func1();
        func2();
    
        return 0;
    }
    		

    سنحصل على النتيجة التالية عند التشغيل.

    func1 is called
    func2 is called
    		


    المثال التالي يوضح المشكلة التي قد يسببها تضمين كل محتوى النطاق.

    في المثال التالي قمنا بتعريف دالة إسمها printMsg() و نطاق إسمه harmash يحتوي على دالة إسمها printMsg() أيضاً.
    بعدها قمنا بتضمين كل محتوى النطاق harmash و بالتالي أصبح هناك دالتين printMsg() في نفس المكان مما سيؤدي لمشكلة عند محاولة استدعاء الدالة بهذا الشكل printMsg(); سببها تضارب الأسماء عند التشغيل.

    المثال الثاني

    Main.cpp
    #include <iostream>
    
    // printMsg() هنا قمنا بتعريف دالة عامة إسمها
    void printMsg()
    {
    	std::cout << "harmash::printMsg is called \n";
    }
    
    // printMsg() يحتوي على إسمها harmash هنا قمنا بتعريف نطاق إسمه
    namespace harmash
    {
        void printMsg()
    	{
    		std::cout << "harmash::printMsg is called \n";
    	}
    }
    
    // الأمر الذي سيؤدي لحدوث مشكلة تضارب الأسماء عند محاولة harmash هنا قمنا بتضمين كل الكود الموجود في النطاق
    // موجودتين في نفس المكان printMsg() لأنه بالنسبة للمترجم أصبح هناك دالتين إسمهما printMsg() استدعاء الدالة
    using namespace harmash;
    
    int main()
    {
    	// الأمر الذي سيسبب مشكلة تضارب الأسماء printMsg() هنا حاولنا استدعاء الدالة
    	printMsg();
    	
        return 0;
    }
    		

    سيظهر الخطأ التالي عند التشغيل بسبب السطر رقم 25 لأن المترجم حائر و لا يعرف أي دالة printMsg() تريده أن ينفذ لك.

    25 | error: call of overloaded 'printMsg()' is ambiguous

    وضع إسم مختصر للنطاق

    في حال كان إسم النطاق كبيراً يمكنك استخدام الكلمة namespace لوضع إسم مختصر له.
    ما تفعله ببساطة هو تعريف نطاق جديد تعطيه إسم مختصر و تجعله يساوي النطاق الذي يملك إسم كبير.


    الشكل العام لوضع إسم مختصر للنطاق

    namespace very_long_namespace_name 
    {
    
    }
    
    namespace alias_name = very_long_namespace_name;
    	

    • مكان الكلمة very_long_namespace_name تضع إسم النطاق الذي تنوي وضع إسم مختصر له.
    • مكان الكلمة alias_name تضع الإسم المختصر الذي تريد وضعه للناطق.


    في المثال التالي قمنا بتعريف نطاق إسمه harmashcom يحتوي على دالة printMsg().
    بعدها قمنا بتعريف إسم مختصر للنطاق harmashcom إسمه hc و من ثم قمنا باستدعاء الدالة من خلاله.

    مثال

    Main.cpp
    #include <iostream>
    
    // يحتوي على دالة واحدة harmashcom هنا قمنا بتعريف نطاق إسمه
    namespace harmashcom
    {
        void printMsg()
    	{
    		std::cout << "printMsg is called \n";
    	}
    }
    
    // harmashcom هنا قمنا بتعريف إسم مختصر للنطاق
    namespace hc = harmashcom;
    
    int main()
    {
    	// harmashcom من خلال الإسم المختصر الذي وضعناه للنطاق printMsg() هنا قمنا باستدعاء الدالة
        hc::printMsg();
    	
        return 0;
    }
    		

    سنحصل على النتيجة التالية عند التشغيل.

    printMsg is called
    		
    إعلان

    Eqla3Tech.com

    شروحات مكتوبة حول لغات البرمجة و تقنية المعلومات باللغة العربية مقدمة من إقلاع تك.

    لغة جافا لغة ++C قواعد البيانات نظام ويندوز نظام لينكس الشبكات تقنية المعلومات الأمن السيبراني

    الدورات

    أدوات مساعدة

    الأقسام

    دورات
    مقالات أسئلة مشاريع كتب