المؤشرات والمراجع
جزء من قسم Object Oriented Programming في رحلة C++ على Coddy — الدرس 13 من 104.
الآن بعد أن فهمت ذاكرة الـ stack والـ heap، دعنا نستكشف الأدوات التي تتيح لك العمل مع مواقع الذاكرة مباشرةً: المؤشرات (pointers) والمراجع (references).
يقوم المؤشر بتخزين عنوان الذاكرة لمتغير آخر. تقوم بالتصريح عنه باستخدام * وتحصل على العنوان باستخدام &.
int value = 42;
int* ptr = &value; // ptr يحمل عنوان value
std::cout << ptr; // يطبع عنوان الذاكرة
std::cout << *ptr; // إلغاء المرجعية: يطبع 42الـ مرجع هو اسم مستعار لمتغير موجود بالفعل. وبمجرد ربطه، فإنه يشير دائماً إلى ذلك المتغير. يتم التصريح عنه باستخدام &.
int value = 42;
int& ref = value; // ref هو اسم مستعار لـ value
ref = 100; // يغير value إلى 100
std::cout << value; // يطبع 100الاختلافات الرئيسية:
| المؤشرات (Pointers) | المراجع (References) |
|---|---|
| يمكن أن تكون فارغة (null) | يجب تهيئتها |
| يمكن إعادة تعيينها | لا يمكن إعادة ربطها |
استخدم * للوصول إلى القيمة | الوصول إلى القيمة مباشرة |
| يمكن أن تشير إلى لا شيء | صالحة دائماً |
كلاهما ضروري لتمرير الكائنات إلى الدوال بكفاءة دون نسخها، وللعمل مع الذاكرة المخصصة في الكومة (heap). المراجع أكثر أماناً وبساطة، بينما توفر المؤشرات مرونة أكبر عندما تحتاج إلى إعادة التعيين أو التحقق من القيمة الفارغة (null).
التحدي
سهللنقم ببناء نظام بسيط للتلاعب بالقيم يوضح كيف تعمل المؤشرات (pointers) والمراجع (references) بشكل مختلف عند تعديل البيانات.
ستقوم بإنشاء ملفين لتنظيم الكود الخاص بك:
ValueOps.h: قم بتعريف ثلاث دوال تقوم بتعديل قيم الأعداد الصحيحة بطرق مختلفة:doubleByPointer(int* ptr)— تأخذ مؤشراً وتضاعف القيمة التي يشير إليها.tripleByReference(int& ref)— تأخذ مرجعاً وتضاعف القيمة ثلاث مرات.swapValues(int* a, int* b)— تأخذ مؤشرين وتقوم بتبديل القيم التي يشيران إليها.
main.cpp: اقرأ عددين صحيحين من المدخلات، ثم استعرض كلاً من المؤشرات والمراجع:- اطبع القيم الأصلية:
"Original: <first> <second>" - استخدم
doubleByPointerعلى القيمة الأولى، ثم اطبع:"After double: <first>" - استخدم
tripleByReferenceعلى القيمة الثانية، ثم اطبع:"After triple: <second>" - استخدم
swapValuesلتبديل كلتا القيمتين، ثم اطبع:"After swap: <first> <second>"
- اطبع القيم الأصلية:
عند استدعاء الدوال باستخدام المؤشرات، تذكر استخدام عامل العنوان (&) لتمرير عنوان المتغير. أما المراجع فتعمل بشكل طبيعي أكثر — فقط قم بتمرير المتغير مباشرة.
قم بتضمين ملف الرأس الخاص بك في main.cpp باستخدام #include "ValueOps.h".
ورقة مرجعية
يخزن المؤشر (pointer) عنوان الذاكرة لمتغير آخر. يتم التصريح عنه باستخدام * والحصول على العنوان باستخدام &:
int value = 42;
int* ptr = &value; // ptr holds the address of value
std::cout << ptr; // Prints the memory address
std::cout << *ptr; // Dereference: prints 42أما المرجع (reference) فهو اسم مستعار لمتغير موجود بالفعل. يتم التصريح عنه باستخدام &:
int value = 42;
int& ref = value; // ref is an alias for value
ref = 100; // Changes value to 100
std::cout << value; // Prints 100الاختلافات الجوهرية:
| المؤشرات (Pointers) | المراجع (References) |
|---|---|
| يمكن أن تكون فارغة (null) | يجب تهيئتها عند الإعلان عنها |
| يمكن إعادة تعيينها لمتغير آخر | لا يمكن تغيير ارتباطها بمتغير آخر |
استخدم * للوصول إلى القيمة | الوصول إلى القيمة مباشرة |
| يمكن ألا تشير إلى شيء | دائماً صالحة |
عند استدعاء الدوال باستخدام المؤشرات، استخدم عامل العنوان (&) لتمرير عنوان المتغير. أما المراجع فتعمل مباشرة — فقط قم بتمرير المتغير.
جرّب بنفسك
#include <iostream>
#include "ValueOps.h"
using namespace std;
int main() {
// قراءة عددين صحيحين من المدخلات
int first, second;
cin >> first;
cin >> second;
// طباعة القيم الأصلية
cout << "Original: " << first << " " << second << endl;
// TODO: استخدم doubleByPointer على القيمة الأولى (مرر العنوان باستخدام &)
// TODO: الطباعة بعد المضاعفة (double)
// TODO: استخدم tripleByReference على القيمة الثانية (مرر المتغير مباشرة)
// TODO: الطباعة بعد المضروب في ثلاثة (triple)
// TODO: استخدم swapValues لتبديل القيمتين (مرر العناوين باستخدام &)
// TODO: الطباعة بعد التبديل (swap)
return 0;
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
1أساسيات الـ OOP
الملفات الخارجيةبناء وتجميع (Compilation) لغة C++ملفات الـ Header وملفات الـ Sourceالـ Namespaces والـ Scopeمقدمة في الـ OOP في C++الـ Classes مقابل الـ Objectsالمؤشر 'this'الـ Methods (الدوال الأعضاء)الـ Attributes (بيانات الأعضاء)أساسيات الـ Ctors والـ Dtorsمراجعة - آلة حاسبة بسيطة4خصائص الـ Class
أعضاء الـ Instance مقابل الـ Staticدوال الـ Getters والـ Settersدوال الأعضاء الثابتة (Const)الكلمة المفتاحية Mutableالدوال والمتغيرات الساكنة (Static)الدوال والفئات الصديقة (Friend)مراجعة - مدير الحساب البنكي7الوراثة
الوراثة الأساسيةمستويات الوصول في الوراثةترتيب استدعاء الـ Ctor والـ Dtorإعادة تعريف الدوال (Method Overriding)الدوال الافتراضية والـ VTableالوراثة المتعددةالوراثة الافتراضيةمراجعة - هيكلية الموظفين10نظرة عامة على STL
نظرة عامة وفلسفة STLحاويات STLالـ Iteratorsخوارزميات STLالـ Functors وتعبيرات Lambdaمراجعة - تكرار الكلمات13أنماط التصميم - الجزء الأول
مقدمة في أنماط التصميمنمط Singletonنمط Factory و Abstract Factoryنمط Builderنمط Observerنمط Strategy2إدارة الذاكرة
ذاكرة Stack مقابل Heapالمؤشرات والمراجعالذاكرة الديناميكية (new/delete)المؤشرات الذكية في C++RAII في C++مراجعة - مدير المصفوفات الديناميكية5التغليف (Encapsulation)
محددات الوصول في C++محددات الوصول بشكل متعمقإخفاء المعلوماتStruct مقابل Classالأصناف المتداخلة والداخليةمراجعة - نظام سجلات الطلاب8تعدد الأشكال (Polymorphism)
تعدد الأشكال: وقت التجميع مقابل وقت التشغيلالتحميل الزائد للدوال (Function Overloading)مراجعة الدوال الافتراضية (Virtual Functions)الدوال الافتراضية البحتة (Pure Virtual Functions)الأصناف المجردة (Abstract Classes)تصميم الواجهات (Interface) في C++التحويل الديناميكي (Dynamic Casting) و RTTIملخص - حاسبة الأشكال11مفاهيم OOP المتقدمة
التركيب مقابل الوراثةالـ Mixins عبر CRTPنمط Pimplمحو النوع (Type Erasure)أصناف Enum والأنواع القويةمعالجة الاستثناءات في OOPتسلسلات الاستثناءات المخصصة14أنماط التصميم - الجزء الثاني
نمط الأمرنمط المحولنمط المزيننمط قالب الطريقةنمط الحالةنمط التركيبRAII كنمط3المنشئات والموادم
المنشئ الافتراضيالمنشئ ذو المعاملاتمنشئ النسخمنشئ النقلقوائم تهيئة المنشئالمنشئات المفوضةتعمق في الموادمقاعدة الثلاثة / الخمسة / الصفرمراجعة - فئة String6تحميل العوامل (Operator Overloading)
مقدمة في تحميل العواملتحميل العوامل الحسابيةتحميل عوامل المقارنةعوامل Streamتحميل عامل التعيينتحميل العوامل [] و ()عوامل تحويل النوعمراجعة - Matrix Class9القوالب
قوالب الدوالقوالب الأصنافتخصيص القوالبالقوالب المتغيرةأساسيات SFINAE و Type Traitsمراجعة - الحاويات العامة