سؤال

هل هذا هو نفسه:

int foo(bar* p) {
  return p->someInt();
}

و

int foo(bar& r) {
  return r.someInt();
}

تجاهل إمكانات المؤشر الفارغ. هل هاتان الوظيفتان متطابقتان وظيفيًا بغض النظر عما إذا someInt() افتراضي أو إذا تم تمريره bar أو فئة فرعية من bar?

هل هذا شريحة أي شيء:

bar& ref = *ptr_to_bar;
هل كانت مفيدة؟

المحلول

لم يتم تحديد مراجع C ++ عن قصد في المعيار الذي سيتم تنفيذه باستخدام المؤشرات. يشبه المرجع "مرادفًا" لمتغير أكثر من مؤشره. تفتح هذه الدلالات بعض التحسينات الممكنة للمترجم عندما يكون من الممكن أن ندرك أن المؤشر سيكون مبالغة في بعض المواقف.

بضع اختلافات أخرى:

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

نصائح أخرى

تجاهل كل السكر النحوي والإمكانيات التي يمكن القيام بها مع واحد وليس مع الآخر والفرق بين المؤشرات والمراجع الموضحة في إجابات أخرى (لأسئلة أخرى) ... نعم هذان الشخصان هو نفسه بالضبط! كلاهما يدعو الوظيفة وكلاهما يتعاملان مع الوظائف الافتراضية على قدم المساواة.

ولا ، خطك لا يقطع. إنه مجرد ربط الإشارة مباشرة إلى الكائن الذي أشار إليه مؤشر.

بعض الأسئلة حول سبب رغبتك في استخدام واحد على الآخر:

بدلاً من محاولة التوصل إلى اختلافات بنفسي ، أقوم بتفويضك إلى أولئك في حالة رغبتك في معرفة ذلك.

المرجع هو مؤشر ثابت أي ، لا يمكنك تغيير المرجع للإشارة إلى كائن آخر. إذا قمت بتغيير ، فإن قيمة الكائن الإحالة تتغير.

لـ Ex:

       int j = 10;
       int &i = j;
       int l = 20;
       i = l; // Now value of j = 20

       int *k = &j;
       k = &l;   // Value of j is still 10

لم أستخدم C ++ منذ فترة طويلة ، لذلك لن أحاول حتى الإجابة على سؤالك (آسف) ؛ ومع ذلك ، نشر إريك ليبرت للتو مقالة ممتازة حول المؤشرات/المراجع التي اعتقدت أنني سأوجهك إليها.

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

من المهم أيضًا رؤية الفرق الدلالي:

  • استخدم مرجعًا عندما تقوم بتمرير الكائن بشكل طبيعي فعليًا - لكنه كبير جدًا بحيث يكون من المنطقي تمرير مرجع إلى الكائن بدلاً من إنشاء نسخة (إذا لم تقم بتعديل الكائن).
  • استخدم مؤشرًا عندما تريد التعامل مع عنوان الذاكرة بدلاً من الكائن.

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

التقطيع هو عندما يتم تعيين كائن مشتق (نسخ) إلى كائن فئة أساسية - تخصص الفئة المشتقة "شرائح". لاحظ أنني قلت هدف يتم نسخه ، نحن لا نتحدث عن نسخ/تعيين مؤشرات ، ولكن الأشياء نفسها.

في مثالك ، هذا لا يحدث. أنت مجرد إلغاء تحديد مؤشر إلى كائن شريط (مما يؤدي إلى استخدام كائن شريط) يتم استخدامه كـ RVALUE في تهيئة مرجعية. لست متأكداً من أنني حصلت على مصطلحتي الصحيح ...

كما ذكر الجميع ، في مراجع التنفيذ والمؤشرات متشابهة إلى حد كبير. هناك بعض التحذيرات البسيطة:

  • لا يمكنك تعيين NULL إلى مرجع (ذكر Shoosh هذا): هذا أمر مهم نظرًا لعدم وجود قيمة مرجعية "غير محددة" أو "غير صالحة".

  • يمكنك تمرير متغير مؤقت مثل أ مقدار ثابت الرجوع ، ولكن ليس من القانوني نقل مؤشر إلى مؤقت.

على سبيل المثال ، هذا جيد:

class Thingy; // assume a constructor Thingy(int,int)
void foo(const Thingy &a)
{ 
   a.DoSomething();
}

void bar( ) 
{
  foo( Thingy(1,2) );
}

لكن معظم المترجمين سوف يشكون

void foo2( Thingy * a);

void bar2()
{
  foo( &Thingy(1,2) );
}
  • أخذ عنوان متغير للحصول على مؤشر يجبر المترجم على حفظه في الذاكرة. تعيين مرجع إلى متغير محلي فقط يخلق مرادفًا ؛ في بعض الحالات ، قد يسمح هذا للمترجم بالاحتفاظ بالبيانات على السجل وتجنب أ متجر الحمل. ومع ذلك ، ينطبق هذا فقط على المتغيرات المحلية - بمجرد تمرير شيء ما كمعلمة بالرجوع إليها ، لا يوجد تجنب حفظه في المكدس.

 

void foo()
{
   int a = 5;
   // this may be slightly more efficient
   int &b = a;
   printf( "%d", ++b );
   // than this
   int *c = &a;
   printf( "%d", ++(*c) );
}
  • وبالمثل ، فإن __restrict الكلمة الرئيسية لا يمكن تطبيقها على المراجع ، فقط المؤشرات.

  • لا يمكنك القيام بحساب مؤشر مع المراجع ، لذلك إذا كان لديك مؤشر في صفيف ، فيمكن أن يكون العنصر التالي في الصفيف من خلال P+1 ، وهو مرجع فقط على الإطلاق في شيء واحد في حياته بأكملها.

من الواضح أن الوظائف ليست "متشابهة" ، ولكن فيما يتعلق بالسلوك الافتراضي ، فإنها ستتصرف بشكل مشابه. فيما يتعلق بالتقطيع ، يحدث هذا فقط عندما تتعامل مع القيمة ، وليس المراجع أو المؤشرات.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top