الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

[ تمت الإجابة ]الدالة friendفي oop

بدأه طموحة بلا حدود في 7 مارس 2013 · 5 رد · 635 مشاهدة · في الأسئلة المجابة
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

السلام عليكم 

انا اتابع الدورة المفصلة في oop التي في هذا المنتدى الرائع

وجزاء الله كل الخير من ينشر مثل هذه الدروس والدوات المفيده جدا

بس عندي سوال في الداله friend

لماذا استخدمنا المرجع للكائن عند التمرير في الداله ولم نستخدم الكائن مباشرة

كما في الكود:

class count
{
friend void setx (count&,int);   //تعريف لمرجع كائن
private:
int x;
public:
count(){x=0;}
void print()const
{
cout<<x<<endl;
}};
void setx (count &c,int val)
{
c.x=val;
}
int main()
{
count counter;
counter.print();
setx(counter,8);
counter.print();

	  system("PAUSE");
	  return 0;
}

ياريت توضيح مع جزيل الشكر والتقدير

كثيــــرووون هــــــــم أولئـكــــــ الـــــــذيـــن يسعــــووون جــــــاهــــــدين مــــن أجـــــل التميـــــز ولكـــــــن!!!!

هيهــــــــات فالقمــــــــة لا تتســـــع إلا لـــــــواحد ومـــــع ذالكــــــــ فلكــــــل مجتهــــــــد نصيــــب

#2

يبدولي أن السؤال لاعلاقة له بالـfriend بل بطرق تمرير الكائن.

لو مررتي الكائن فإنّك ستمررين نسخة من هذا الكائن وليس الكائن نفسه. فأي عمليات تجرينها على النسخة لن تؤثّر على الأصل. على العكس لو مررتي مرجع للكائن أو عنوانه (مؤشّر).

في كل الأمثلة هناك class اسمه Foo في عنصر اسمه member ووظيفة setMember لتغيير قيمته وgetMember للحصول على قيمته وهناك دالة اسمها try_to_change_foo تحاول تغيير قيمة هذا الكائن الممرر لها.

1. تمرير نسخة من الكائن

مثال:

#include <iostream>
using namespace std;

class Foo {
private:
    int member;
public:
    void setMember(const int member)
    {
        this->member = member;
    }
    int getMember(void) const
    {
        return member;
    }
};

void try_to_change_foo(Foo foo)
{
    foo.setMember(2);
}

int main(int argc, char **argv)
{
    Foo foo;
    foo.setMember(1);
    cout << foo.getMember() << endl;

    try_to_change_foo(foo);
    cout << foo.getMember() << endl;

    return 0;
}
عند تشغيل البرنامج سيطبع:

11

لم تتمكن الدالة try_to_change_foo من تغيير قيمة العنصر في الكائن. ذلك لأننا فعلياً لم نمرر الكائن نفسه بل مررنا "نسخه أخرى منه" لن تتأثر بالعمليات التي نجريها على الكائن.

2. تمرير مرجع

مثال:

#include <iostream>
using namespace std;

class Foo {
private:
    int member;
public:
    void setMember(const int member)
    {
        this->member = member;
    }
    int getMember(void) const
    {
        return member;
    }
};

void try_to_change_foo(Foo& foo)
{
    foo.setMember(2);
}

int main(int argc, char **argv)
{
    Foo foo;

    foo.setMember(1);
    cout << foo.getMember() << endl;

    try_to_change_foo(foo);
    cout << foo.getMember() << endl;

    return 0;
}

الناتج:

12

أمكن try_to_change_foo هذه المرّة أنّ تغير الكائن.

3. تمرير المؤشّر

هناك أيضاً طريقة التمرير بالمؤشّر (تمرير عنوان الكائن). المثال السابق سيكون:

#include <iostream>
using namespace std;

class Foo {
private:
    int member;
public:
    void setMember(const int member)
    {
        this->member = member;
    }
    int getMember(void) const
    {
        return member;
    }
};

void try_to_change_foo(Foo* foo)
{
    foo->setMember(2); // أو (*foo).setMember(2)
}

int main(int argc, char **argv)
{
    Foo foo;

    foo.setMember(1);
    cout << foo.getMember() << endl;

    try_to_change_foo(&foo);
    cout << foo.getMember() << endl;

    return 0;
}

الناتج:

12

لها نفس التأثير. لكن من الأفضل "دوماً" التمرير بالمرجع مالم تكون هناك سبب يجبر على التمرير المؤشر، لايحضرني مثال عليه.

1
#3
Mr.B كتب:

لها نفس التأثير. لكن من الأفضل "دوماً" التمرير بالمرجع مالم تكون هناك سبب يجبر على التمرير المؤشر، لايحضرني مثال عليه.

تمرير Null value مثلا؟ :)

1

Everything will be fine when we TALK LESS, DO MORE


#4

مش عارفه كيف اشكرك استاذ  دائما ترد على مشاركاتي وتوضح باسلوب رائع

لكن من فضلك   اريد ان اعرف  ما فائده استخدام داله friend في الكائنات ومتي نحتاج لاستخدامها

 

وكلامك صحيح كان سوالي عن التمرير بالمرجع  ياريت توضح لي او تدلني على شرح كامل عن المرجع والمواشرات  والفرق بينها  والفرق  عند تمريرها في الدوال

وياريت تشرح لي الفرق  لان اسلوبك واضح جدا بالامثله

 

وربي يجزيك الجنة

كثيــــرووون هــــــــم أولئـكــــــ الـــــــذيـــن يسعــــووون جــــــاهــــــدين مــــن أجـــــل التميـــــز ولكـــــــن!!!!

هيهــــــــات فالقمــــــــة لا تتســـــع إلا لـــــــواحد ومـــــع ذالكــــــــ فلكــــــل مجتهــــــــد نصيــــب

#5
MoHaMMaD Pro كتب:

تمرير Null value مثلا؟ :)

+1 نقطه جميلة، عندما نريد جعل تمرير الكائن اختياري.

أي شيء مشار إليه بأنه خاص private بالـclass فلن يمكن الوصول له من خارج الـclass. لكن عند الإشارة لدالة أو class معين بأنه "صديق" friend فهذا سيمكنّ تلك الدالة أو الكائن من الوصول للعناصر الخاصة بهذا الكائن:

مثال:

#include <iostream>
using namespace std;

class Foo {
    friend void i_am_a_friend_of_foo(Foo& foo);
    int private_member;
public:
    Foo(void) {
        private_member = 0;
    }
    
    int getPrivateMember(void) const {
        return private_member;
    }
};

void i_am_a_friend_of_foo(Foo& foo)
{
    foo.private_member = 10;
}

int main(int argc, char **argv)
{
    Foo foo;
    
    cout << foo.getPrivateMember() << endl;
    i_am_a_friend_of_foo(foo);
    cout << foo.getPrivateMember() << endl;

    return 0;
}

المصرّف compiler لن يعتبر ماقمنا به خطأ، محاولة i_am_a_friend_of_foo الوصول لعنصر خاص في Foo، لأّن Foo أخبر بأن هذه الدالة "صديقة":

...    friend void i_am_a_friend_of_foo(Foo& foo);...

لو أزلنا هذا السطر فسيعطي خطأ لمحاولة الوصول لعنصر خاص مثل:

error: 'int Foo::private_member' is private

بالنسبة للفرق بين المؤشرات فتقريباً جميع الفروقات التي تحضرني غطتها الأمثلة التي وضعتها.

#6

شكرا استاذ  استفدت جدا

لكن ياريت لو حد يدلني على شرح كامل عن المراجع والمؤاشرات

كثيــــرووون هــــــــم أولئـكــــــ الـــــــذيـــن يسعــــووون جــــــاهــــــدين مــــن أجـــــل التميـــــز ولكـــــــن!!!!

هيهــــــــات فالقمــــــــة لا تتســـــع إلا لـــــــواحد ومـــــع ذالكــــــــ فلكــــــل مجتهــــــــد نصيــــب

مواضيع مشابهة