PDA

View Full Version : مشکل با سربارگذاری عملگرها



amiref
جمعه 25 تیر 1389, 23:15 عصر
با سلام
کسی می دونه چرا در بارگذاری بعضی توابع مانند زیر در نوع برگشتی تابع از & استفاده می کنیم ؟


class StringClass
{
public:
...
void someProcessing( );
...
StringClass& operator=(const StringClass& rtSide);
...
private:
char *a;//Dynamic array for characters in the string
int capacity;//size of dynamic array a
int length;//Number of characters in a
};

PC2st
شنبه 26 تیر 1389, 00:08 صبح
تا بتوان چنین کدهایی نوشت:


StringClass strc;
(strc = "1234") = "11";
(strc = "1234").someProcessing ();
StringClass strccc;
strccc = strc = "11111";

Salar Ashgi
شنبه 26 تیر 1389, 00:38 صبح
اصطلاحا بهش میگن جهت فرخوانی آبشاری member function های کلاس .

amiref
شنبه 26 تیر 1389, 01:06 صبح
دوستان من می دونم که از & برای operator chaining استفاده میشه ، اما نمیدونم مکانیزم عملگر & در اینجا چیه و چرا برای operator chaining از این عملگر استفاده می کنند . امیدوارم منظورم را فهمیده باشید . اگر متوجه منظور من شدید لطفا من را کمک کنید .

PC2st
شنبه 26 تیر 1389, 11:49 صبح
عملگر & را از جهاتی می‌توانید مشابه اشاره‌گرهای ثابت (‪const T*‬) در نظر گرفت.


int i = 0;
int j = i;
int& k = i;
++i;
++j;
++k;
i یک متغیر با مقدار صفر است.
j متغیری است که مقدار متغیر i در آن کپی می‌شود. پس متغیر j چیزی جدای از متغیر i است.
k متغیری است که معادل متغیر i است. در اینحالت، مقدار متغیر i در متغیر k کپی نمی‌شود، بلکه خود متغیر i به متغیر k نسبت داده می‌شود. بنابراین توسط متغیر k می‌توان به مقدار متغیر i دسترسی مستقیم داشت.

در سربارگذاری عملگر = هم به همین صورت است، یعنی وقتی نوع بازگشتی آن را بصورت & مشخص می‌کنیم، دسترسی مستقیم به مقدار آن داریم، در غیر اینصورت، دسترسی به یک مقدار کپی‌شده از آن را خواهیم داشت و هر تغییری که بر روی آن مقدار کپی‌شده انجام دهیم، تاثیری در مقدار اصلی نخواهد گذاشت.

این نمونه مثال:

#include <iostream>

class A
{
int i;

public:

void increment ();
A& operator= (int value);
void print () const;
};

void A::increment () { ++this->i; }
A& A::operator= (int value) { this->i = value; return *this; }
void A::print () const { std::cout << this->i << std::endl; }

int main ()
{
A a;
(a = 2).increment ();
a.print ();
}برنامه را کامپایل و اجرا کنید. مقدار ۳ چاپ می‌شود، چون در بدنهٔ تابع main ما توسط تابع increment مقدار اصلی از شیئ کلاس را تغییر می‌دهیم.
سپس اعلان تابع ‪operator=‬ را تغییر داده و علامت & را از آنها بر دارید، سپس دوباره برنامه را کامپایل و اجرا کنید. مقدار ۲ چاپ می‌شود. چون در این حالت، در بدنهٔ تابع main ما توسط تابع increment در واقع مقدار کپی‌شده را تغییر داده‌ایم نه مقدار اصلی را...

drstrike
شنبه 26 تیر 1389, 12:33 عصر
کسی می دونه چرا در بارگذاری بعضی توابع مانند زیر در نوع برگشتی تابع از & استفاده می کنیم ؟


توابعی که یک نوع رو برمی گردانند، دو نوعند: 1- بازگشت از نوع مقدار 2- بازگشت از نوع ارجاع

توابع بازگشت از نوع مقدار، راست مقدارند؛ یعنی این توابع در سمت راست یک عمل انتساب قرار می گیرند و یک مقدار را بازگشت می دهند. مثال: ;()n=func

توابع بازگشت از نوع ارجاع، چپ مقدارند؛ یعنی این توابع در سمت چپ یک عمل انتساب قرار می گیرند و یک متغیر را بازگشت می دهند(!). مثال: ;()n=func


int& func()
{
.....

return s;
}

int main()
{
func()=10;
}


در واقع (در برنامه فوق) تابع func مقدار s را بر نمی گرداند؛ بلکه خود متغیر s را بر می گرداند.

تذکر: در توابع بازگشت از نوع ارجاع هیچ وقت یک متغیر محلی را بازگشت ندهید؛ زیرا وقتی تابع به پایان برسد، متغیر محلی نیز نابود خواهد شد. (چقد ادبیاتم خوب بوده خبر نداشتم :لبخند: )

Salar Ashgi
شنبه 26 تیر 1389, 13:53 عصر
همانطور که دوستان هم گفتن ، این عملگر در واقع همون وظیفه اشاره گری خودش یعنی

Reference Type رو انجام میده .

amiref
شنبه 26 تیر 1389, 15:04 عصر
با تشکر بسیار از دوست عزیز PC2st که جواب خیلی خوب و مثال فوق العاده ای را مطرح کردند .
اما در مورد جواب دوستمون drstrike ، اولا ممنون به خاطر اطلاعاتی که به من افزودید . اما پس از خواندن جواب شما سوال دیگری برایم پیش آمد :
با توجه به بحثی که شما مطرح کردید ، در سوال من که چنین حالتی پیش نمی آید ( که نیاز به استفاذه از خاصیت چپ مقدار بودن مقدار برگشتی تابع باشد ) پس چرا مقدار بازگشتی به صورت reference است ؟
ممنون می شم اگه جواب بدید .

amiref
شنبه 26 تیر 1389, 15:08 عصر
به کد زیر توجه کنید :





#include <iostream>
#include <conio.h>
using namespace std;

class loc
{
private:
int longitude;
int latitude;
public:
loc() {} //needed to construct temporaries
loc(int lg, int lt)
{
longitude = lg;
latitude = lt;
}

void show()
{
cout << longitude << "\t";
cout << latitude << endl;
}

loc operator+(loc op2);
loc operator-(loc op2);
loc operator=(loc op2);
loc operator++();
};
//******************
//overload + for loc
loc loc::operator+(loc op2)
{
loc temp;
temp.longitude = op2.longitude + longitude;
temp.latitude = op2.latitude + latitude;
return temp;
}
//********** overload - for loc ***********
loc loc::operator-(loc op2)
{
loc temp;
//notice order of operand
temp.longitude = longitude - op2.longitude;
temp.latitude = latitude - op2.latitude ;
return temp;
}
// overload assign for loc
loc loc::operator=(loc op2)
{
longitude = op2.longitude;
latitude = op2.latitude ;
return *this; // return object that generated call
}
//******* overload prefix ++ for loc
loc loc::operator++()
{
longitude ++;
latitude ++ ;
return *this; //return object that generated call
}
//**********************
int main()
{

loc ob1(10, 20), ob2(5, 30), ob3(90, 90);
cout << "ob1=";
ob1.show(); //display 10 , 20
cout << "ob2=";
ob2.show(); //display 5, 30
++ob1;
cout << "ob1=";
ob1.show(); //display 11 , 21
ob2 = ++ob1;
cout << "ob1=";
ob1.show(); //display 12 , 22
cout << "ob2=";
ob2.show(); //display 12, 22
ob1 = ob2 = ob3; //multiple assignment
cout << "ob1=";
ob1.show(); //display 90, 90
cout << "ob2=";
ob2.show(); //display 90, 90
cout << "ob3=";
ob3.show(); //display 90, 90
getch();
return 0;
}







چرا با بوجود overload شدن عملگر "=" بدون استفاده از & این عملگر درست کار می کند ؟

PC2st
شنبه 26 تیر 1389, 16:40 عصر
باید هم درست کار کند، چون درسته که از مقدار بازگشتی reference استفاده نشده ولی چون عمل کپی صورت می‌گیره و مقادیر توسط کپی‌کردن به یکدیگر، مقداردهی می‌شوند. اگر می‌خواهید تفاوت را بهتر متوجه شوید، در تابع main این دستور را وارد کنید:


++(ob2 = ob3);

چون شما نوع بازگشتی عملگر ++ را از نوع ارجاعی در نظر نگرفته‌اید، پس عملگر ++ تغییری بر روی مقدار ob2 نخواهد داد، اما اگر از نوع بازگشتی ارجاعی (reference) برای عملگر ++ استفاده کرده بودید، مقدار ob2 هم تغییر می‌کرد.

amiref
جمعه 01 مرداد 1389, 14:34 عصر
سلام
میشه یه توضیح کامل در مورد سربارگذاری عملگر های << و >> بدهید ؟ دلیل سه بار استفاده از & در سربارگذاری هر یک از این عملگرها چیست ؟
20 friend ostream& operator <<(ostream& outputStream, const Money& amount);
21 friend istream& operator >>(istream& inputStream, Money& amount);

amiref
جمعه 01 مرداد 1389, 14:35 عصر
سلام
میشه یه توضیح کامل در مورد سربارگذاری عملگر های << و >> بدهید ؟ دلیل سه بار استفاده از & در سربارگذاری هر یک از این عملگرها چیست ؟
20 friend ostream& operator <<(ostream& outputStream, const Money& amount);
21 friend istream& operator >>(istream& inputStream, Money& amount);

PC2st
جمعه 01 مرداد 1389, 22:07 عصر
دلیل اینکه پارامترهای ورودی عملگر >> از نوع ارجاعی هستند (یعنی با مقادیر اصلی می‌کنند) این است که از انجام کپی‌های ناخواسته جلوگیری شود (دقیقاً یکی از اهداف انواع ارجاعی).

وظیفهٔ عملگر >> در اینجا چیست؟


aaa << bbb;
در اینجا متغیر aaa با توجه به مقدار bbb تغییر خواهد کرد.

حق تقدم عملگر >> بر چه اساسی است؟ از راست به چپ است و در هر بار انجام عملیات، نتیجهٔ حاصل‌شده بر گشت داده می‌شود:


aaa << bbb << ccc;
در اینجا ابتدا aaa << bbb انجام می‌شود، سپس مقدار aaa برگشت داده می‌شود، دربارهٔ مقدار برگشت داده شده دو حالت پیش خواهد آمد:
۱) اگر مقدار برگشت از نوع ارجاعی باشد، همان مقدار اصلی (یعنی aaa) برگشت داده می‌شود.
۲) اگر مقدار برگشتی از نوع ارجاعی نباشد، یک کپی از مقدار اصلی (یعنی aaa) برگشت داده می‌شود.
اگر این مقدار برگشت داده شده را xxx بنامیم، دستور قبل در ادامه بصورت زیر خواهد شد:


xxx << ccc;
پس اگر xxx حالت ۱ باشد، توسط مقدار ccc مقدار aaa نیز تغییر می‌کند.
اما اگر xxx حالت ۲ باشد، توسط مقدار ccc مقدار کپی‌شده از aaa تغییر می‌کند و تاثیر بر روی خود aaa ندارد، در ادامه نیز، این مقدار کپی‌شده از aaa از بین خواهد رفت، چون به هیچ متغیر دیگری نسبت داده نشده است.