AudaNix

المؤشر الخفى this

1 مشاركة في هذا الموضوع

المؤشر الخفى this

واحد من اكثر اﻻسئلة التى يسألها المبرمج المبتدأ: عندما تُستدعى دالة عضو ، كيف تعرف سي++ ﻷي كائن تنتمي؟ اﻻجابة، ان سي++ تستخدم مؤشر خفى يسمي this ! فلنلقى نظرة على this بتفصيل أكثر.

التالي فئة بسيطة بها متغير عضو من نوع عدد صحيح integer وبها دالة بناء ودوال وصول. ﻻحظ ﻻحاجة لدالة هدم الفئة ﻷن سي++ سوف تحذف متغير العدد الصحيح من الذاكرة بدﻻ منك.

class Simple
{
private:
int m_nID;

public:
Simple(int nID)
{
SetID(nID);
}

void SetID(int nID) { m_nID = nID; }
int GetID() { return m_nID; }
};
والتالي برنامج يستخدم هذة الفئة:
int main()
{
Simple cSimple(1);
cSimple.SetID(2);
std::cout << cSimple.GetID() << std::endl;
}

نظرة عن قرب الى السطر: cSimple.SetID(2); . يبدو ان هذة الدالة لها وسيط واحد فقط، لكن الحقيقة ان لها عدد اثنين وسيط!! عندما تستدعي السطر cSimple.SetID(2); فأن سي++ داخليا تحولة الى SetID(&cSimple, 2); . ﻻحظ انها عملية استدعاء دالة عادية بأضافة وسيط لها وبشكل آلي يتم تمرير عنوان كائن الفئة !

بما أن سي++ تقوم بتحويل كود أستدعاء دالة عضو ، ايضا هي بحاجة الى تحويل الدالة نفسها عندما تكون الدالة العضو كألتالي:

	void SetID(int nID) { m_nID = nID; }

تصبح:

	void SetID(Simple* const this, int nID) { this->m_nID = nID; }

أضافت سي++ وسيط جديد الى الدالة. الوسيط المضاف هو مؤشر الى كائن الفئة التى تعمل فيه الدالة العضو، ودائما يسمي this. أن المؤشر this الخفي بداخل كل دالة عضو فى الفئة والذي يشير دائما الى كائن الفئة التي تعمل الدالة العضو فيه.

ﻻحظ ان m_nID (متغير عضو فى فئة) تم تحويلة الى this->m_nID . بما أن this حاليا تشير الى cSimple الذي هو فى الواقع cSimple->m_nID وهو ما نريدة نحن بالفعل.

فى معظم الوقت لن تحتاج نهائيا hستخدم المؤشر this بشكل صريح، لكن هناك بعض الحاﻻت التى يكون فيها استخدامه مفيداُ:

1. لو ان لديك دالة بناء (او دالة عضو) بها وسيط له نفس اسم متغير عضو فى الفئة، يمكنك التمييز بينهما باستخدام:

class Something
{
private:
int nData;

public:
Something(int nData)
{
this->nData = nData;
}
};

ﻻحظ ان دالة بناء الفئة تأخذ وسيط لهُ نفس اسم متغير عضو فى الفئة. فى هذة الحالة فأن nData تشير الى الوسيطة و this->nData تشير الى المتغير العضو. مع ان الكود سليم مائة بالمائة ، فأن استخدام البادئة m_ قبل كل اسم المتغيرات اﻻعضاء يعطينا حل ممتاز لتجنب ازدواج اﻻسماء واحداث حالة من اﻻرتباك.

2.أحيانا يكون من المفيد ان يكون لديك دالة ترجع الكائن التى تعمل فية. أن أرجاع *this سوف يرجع مرجع الى الكائن الذي تم تمريرة بشكل صريح الى الدالة بواسطة سي++.

أحد استخدامات هذة الميزة انها تسمح بربط سلسلة من الدوال مع بعضها البعض، فتصبح مخرجات الدالة اﻻولي مدخلات لدلة اخري وهكذا! فيما يلى يعتبر كود متقدم ويمكنك تخطية الى نهاية الدرس:

انظر الفئة التالية:

class Calc
{
private:
int m_nValue;

public:
Calc() { m_nValue = 0; }

void Add(int nValue) { m_nValue += nValue; }
void Sub(int nValue) { m_nValue -= nValue; }
void Mult(int nValue) { m_nValue *= nValue; }

int GetValue() { return m_nValue; }
};

لو أضافنا 5 وطرحنا 3 وضربنا 4 فى نفسها، فيجب عليك كتابة الكود التالي:

Calc cCalc;
cCalc.Add(5);
cCalc.Sub(3);
cCalc.Mult(4);

لكن لو اننا جعلنا كل دالة ترجع *this يمكننا ربط استدعائات الدوال مع بعضها البعض. التالي نسخة جديدة من الفئة Calc بدوال مترابطة:

class Calc
{
private:
int m_nValue;

public:
Calc() { m_nValue = 0; }

Calc& Add(int nValue) { m_nValue += nValue; return *this; }
Calc& Sub(int nValue) { m_nValue -= nValue; return *this; }
Calc& Mult(int nValue) { m_nValue *= nValue; return *this; }

int GetValue() { return m_nValue; }
};

ﻻحظ اﻵن ان Add()و Sub() و Mult() ترجع *this الذي يشير الى الى نفس الفئة. احيانا هذا يسمح لنا ببعمل التالي:

Calc cCalc;
cCalc.Add(5).Sub(3).Mult(4);

لقد اختصرنا بكفائة ثلاثة سطور الى سطر واحد! تعال نعرف كيف يعمل ذلك:

اوﻻ يتم استدعاء cCalc.Add(5) التى تضيف القيمة 5 الى m_nValue . ثم ترجع Add() المؤشر *this الذي يشير الى cCalc. ثم الكود التالي اﻵن هو cCalc.Sub(3).Mult(4) . و cCalc.Sub(3) تطرح 3 من m_nValue وترجع cCalc. ثم الكود التالي اﻵن هو cCalc.Mult(4) . و cCalc.Mult(4) تضرب m_nValue في 4 وترجع cCalc ، التى يتم تجاهلها . ونري ان كل دالة يتم تفيذها تقوم بتعديل الفئة cCalc فان cCalc اﻵن تحتوي علي القية ((0 + 5) – 3) * 4) التي تساوي 8 .

على الرغم من مثال متقدم وفية ابداع فان ربط الدوال بهذة الطريقة هو امر معتاد علية فى فئات معالجة السلاسل النصية. على سبيل المثال انه ممكن التحميل الزائد على المؤثر + لدمج السلاسل النصية . لو ان المؤثر + يرجع *this فبالتالي: انه من الممكن كتابة الكود البرمجي التالي:

cMyString = "Hello " + strMyName + " welcome to " + strProgramName + ".";

سوف ندرس التحميل الزائد على المؤثر + (والمؤثرات اﻻخري) فى دروس قادمة.

النقطة المهمة التى نستخلصها من الدرس ان this هو وسيط مؤشر خفى فى اي دالة عضو . غالبا ﻻحاجة للوصول الية مباشرا. ومن الجدير بالذكر ان this هو مؤشر ثابت const pointer -- أى يمكنك تغيير قيمة الكائن الذي يشير الية ولكن ﻻ يمكنك تغييره لكي يشير الى شئ آخر.

تم تعديل بواسطه محمد عودة
تنقيح وتصحيح 2
2

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

  • يستعرض القسم حالياً   0 members

    لا يوجد أعضاء مسجلين يشاهدون هذه الصفحة .