PDA

View Full Version : سوال: سوال در مورد تابع مخرب کلاس



omid2195
چهارشنبه 24 شهریور 1389, 10:12 صبح
سلام:لطفا يه راهنمايي به من بكنيد :


#include <iostream.h>
#include<conio.h>
class car{
float s;
int pow;
public:
car(float i,int j){s=i; pow=j;}
car(){pow=0; s=0;}
car(const car &a);
~car(){cout<<"ob ......";}
car operator+(car a);
car operator-(car a);
car operator=(car a);
car operator++();
car operator++(int x);
car operator--();
void pr(){cout<<"\n\n\n"<<s<<"\t"<<pow<<"\n";}
};
car::car(const car &a){
pow=a.pow;
s=a.s;
}
car car::operator=(car a){
s=a.s;
pow=a.pow;
return *this;
}
car car::operator+(car a){
car temp;
temp.pow=pow+a.pow;
temp.s=s+a.s;
return temp;
}
car car::operator-(car a){
car temp;
temp.pow=pow-a.pow;
temp.s=s-a.s;
return temp;
}
car car::operator++(){
pow++;
s++;
return *this;
}
car car::operator--(){
pow--;
s--;
return *this;
}
car car::operator++(int x){
pow++;
s++;
return *this;
}
int main(){
car f(65.2,20),h(65.3,36),z;
f.pr();
h.pr();
z=f+h;
z.pr();
z++;
z.pr();
++z;
z.pr();
(f+h).pr();
getch();
return 0;
}


تو اين كد واسه (z=f+h;)چهار بار مخرب فراخواني مي شه چرا؟(يكي واسه پارامتره كه وقتي
از ميدان ديد خارج ميشه-دومي واسه شي موقت خوده تابع هسش-سومي وقتي تابع شي رو برمي گردونه يه كپي ازش درست مي شه-تااينجارو درس گفتم؟چهارمي براي چيه؟)
-------------------
z++;اين خط يه مخرب فراخواني ميكنه براي چي؟مگه از اشاره گر براي برگشتش استفاده نمي كنه؟
------------------
پارامتر كاذب int x براي چيه؟و فرق بودن يا نبودنشون در چه؟(هردو تو تابع مثل هم تعريف شدن پس ديگه چرا؟(آيا واسه اينه كه وقتي مي نويسيم z++ ويا ++z تابع عمل كنه؟)
---------------------------------------------------------------------------------------------
با تشكر

PC2st
چهارشنبه 24 شهریور 1389, 22:23 عصر
تو اين كد واسه (z=f+h;)چهار بار مخرب فراخواني مي شه چرا؟(يكي واسه پارامتره كه وقتي
از ميدان ديد خارج ميشه-دومي واسه شي موقت خوده تابع هسش-سومي وقتي تابع شي رو برمي گردونه يه كپي ازش درست مي شه-تااينجارو درس گفتم؟چهارمي براي چيه؟)کد کامپایل شده توسط کامپایلر من، تنها ۳ بار تابع مخرب را برای این مورد صدا می‌زند، چون کامپایلر می‌تواند بهینه‌سازی‌های خاصی را انجام دهد. برای جلوگیری از یک کپی اضافه، می‌توانید آرگومان تابع را از نوع reference تعریف کنید (و چون این آرگومان تغییر نمی‌کند، بهتر است آنرا const نیز تعریف کنید) تا یکی از کپی‌های ناخواسته حذف شود و تابع مخرب یکبار کمتر صدا زده شود.
در مورد اینکه ۴ بار تابع مخرب صدا زده می‌شود، یکی دیگر از مراحل نیز بخاطر عملگر = است که در آنجا یک کپی از شیئ car برگشت داده می‌شود، البته نیازی به اینکار نبود، برای عملگر = به مثال زیر توجه کنید:


x = a;در این حالت اگر عملگر = برای شیئ x یک کپی را برگشت دهد، کل عبارت x = a یک شیئ موقت را بر خواهد گرداند:

(x = a).change();تابع change آن شیئ موقت را تغییر می‌دهد، پس خود x تغییر نمی‌کند. اما اگر عملگر = برای شیئ x یک reference را برگشت می‌داد، کل عبارت x = a به جای یک شیئ موقت، خود x را برگشت می‌داد:

(x = a).change();در اینحالت تابع change مقدار x را نیز تغییر خواهد داد.

z++;اين خط يه مخرب فراخواني ميكنه براي چي؟مگه از اشاره گر براي برگشتش استفاده نمي كنه؟
z++;در اینحالت، ابتدا یک کپی از z گرفته شده و برگشت داده می‌شود و عملگر ++ بر روی z عمل می‌کند. شیئ کپی شده از روی z نیز در انتها نابود می‌شود، به همین خاطر، تابع مخرب صدا زده شده است. البته در کدهای شما در حالت:

++z;نیز تابع مخرب صدا زده می‌شود چونکه برای پیاده‌سازی عملگر مربوطه، یک کپی را برگشت داده‌اید (در حالیکه بهتر بود اینکار را انجام ندهید و به جای آن referenceای از شیئ را برگشت دهید).


پارامتر كاذب int x براي چيه؟و فرق بودن يا نبودنشون در چه؟(هردو تو تابع مثل هم تعريف شدن پس ديگه چرا؟(آيا واسه اينه كه وقتي مي نويسيم z++ ويا ++z تابع عمل كنه؟)پارامتر کاذب int x برای تمایز بین تعریف دو تابع است، یکی برای عملگر z++ و دیگری برای عملگر ++z است. در سی++ فقط از روی لیست آرگومان‌های (پارامترهای) توابع می‌توان بین توابع همنام تمایز ایجاد کرد، بنابراین وجود یک آرگومان کاذب برای تشخیص این تمایز، الزامی است.

omid2195
پنج شنبه 25 شهریور 1389, 08:41 صبح
سلام:ممنون از راهنمايي كه كردين،اما براي من يه سوال پيش امده واينكه:
مگه اشره گر this به شي كه داره عملگر روش كار مي كنه اشاره نمي كنه؟پس وقتي يه مقداري رو با اشاره گر this برگشت داده مي شه ديگه نبايد كپي درست بشه؟اينتور نيست؟
----------------------------------


#include <iostream.h>
#include <conio.h>
class v{
int x,y;
public:
v(){x=0; y=0;}
v(int i,int j){x=i; y=j;}
v(const v &a);
void operator=(v &a);
~v(){cout<<"ob..... ";}
void pr(){cout<<x<<"\t"<<y<<"\n";}
};
v::v(const v &a){
x=a.x;
y=a.y;
}
void v::operator=(v &a){
this->x=a.x;
this->y=a.y;
return;
}
int main(){
v a(7,5),b(2,2),c;
a.pr();
a=b;
a.pr();
getch();
return 0;
}

----------------------------------------------
من تو اين كد مقدار برگشتي تابع رو از this به void تغيير دادم با اين كار ديگه مخرب فراخواني نشد اما وقتي مقدار برگشتي رو به this تغيير مي دم مخرب براخواني مي شه.چرا؟مگه this اشاره گر نيست؟(لطفا يه توضيحي بدين)
-------------------------------------------------------------------------------------
ببخشيد يه سوال ديگه داشتم::خجالت::خجالت::خجالت::خ جالت:
تو خطي كه شما نوشته بوديد(x=f).change())اگه مقدار برگشتي شي موقت باشه xتغيير نمي كنه و شي موقت تغيير مي كنه اما اگه مقدار برگشي this باشه xتغيير مي كنه-تا اينجا درست؟شما گفتين رفرنس بايد بشه تا xتغيير كنه رفرنس كردش چطوري انجام مي شه؟
----------------------------------------------------------------------------------
با تشكر:قلب:
لطفا يه توضيحي بدين و من رو از جهل خارج كنيد.:گیج::گیج::گیج::گیج::گیج:: گیج:

PC2st
پنج شنبه 25 شهریور 1389, 13:36 عصر
مگه اشره گر this به شي كه داره عملگر روش كار مي كنه اشاره نمي كنه؟پس وقتي يه مقداري رو با اشاره گر this برگشت داده مي شه ديگه نبايد كپي درست بشه؟اينتور نيست؟بله درست است، اما شما «اشاره‌گر this» را برگشت نداده‌اید (return this)، شما «مقداری که this به آن اشاره می‌کند» را برگشت داده‌اید (return *this). در ادامه توضیح می‌دهم.


من تو اين كد مقدار برگشتي تابع رو از this به void تغيير دادم با اين كار ديگه مخرب فراخواني نشد اما وقتي مقدار برگشتي رو به this تغيير مي دم مخرب براخواني مي شه.چرا؟مگه this اشاره گر نيست؟(لطفا يه توضيحي بدين)چون this اشاره‌گر هست، اما شما «آدرسی که در this قرار دارد» را برگشت نمی‌دهید، بلکه «مقداری که this به آن اشاره می‌کند» را توسط this* بازگشت می‌دهید.


car* m = this; //no copy
car n = *this; //copy
car& o = *this; //no copy
car p = this; //error! this is a pointer but p is not!
در حالت اول «آدرسی که در this قرار دارد» در m قرار می‌گیرد، اما در حالت دوم و سوم «مقداری که اشاره‌گر this به آن اشاره می‌کند» مورد استفاده قرار می‌گیرد. در حالت آخر، خطا صادر خواهد شد، زیرا this از نوع اشاره‌گر است اما p نیست، هیچگاه نمی‌توان یک اشاره‌گر را در یک متغیر غیر اشاره‌گر قرار داد (البته می‌توان اما نه در حالت عادی).
در ادامه توضیح می‌دهم.


تو خطي كه شما نوشته بوديد(x=f).change())اگه مقدار برگشتي شي موقت باشه xتغيير نمي كنه و شي موقت تغيير مي كنه اما اگه مقدار برگشي this باشه xتغيير مي كنه-تا اينجا درست؟شما گفتين رفرنس بايد بشه تا xتغيير كنه رفرنس كردش چطوري انجام مي شه؟در سی++ نحوهٔ ارجاع به اشیاء چیزی جدای از انواع است، سه حالت در این مورد امکان‌پذیر است:


int x = 10;
int a = x;
int& b = x;
int* c = &x;
x متغیری است که با عدد ۱۰ مقداردهی می‌شود.
a متغیری است که مقدار x در آن کپی می‌شود و مقدار آن نیز ۱۰ خواهد بود. پس مقدار a و x از هم جداست، اگر a تغییر کند، تأثیری بر روی x نخواهد گذاشت.
b یک نام مستعار برای متغیر x است، پس مقدار b و x مشترک است، یعنی اگر مقدار b تغییر کند، مقدار x نیز تغییر می‌کند.
c یک اشاره‌گر به متغیر x است، آدرس متغیر x در c ذخیره می‌شود. از طریق این آدرس می‌توان به مقدار متغیر x دسترسی داشت.
با توجه به این توضیح، به دستورات زیر توجه کنید:


int* i = c;
int j = *c; //int j = x
int& k = *c; //int& k = x
i اشاره‌گری است که آدرس ذخیره‌شده در c را در خود ذخیره می‌کند. هر آدرسی که c به آن اشاره می‌کند، در i ذخیره می‌شود، پس i نیز به همان آدرس اشاره می‌کند. بنابراین i و c هر دو به متغیر x اشاره می‌کنند.
مقدار متغیری که c به آن اشاره می‌کند، در متغیر j کپی می‌شود، دستور خط دوم تقریباً معادل با int j = x است، زیرا c به x اشاره می‌کند و c* یعنی مقدار متغیری که c به آن اشاره می‌کند که همان مقدار متغیر x خواهد بود.
مقدار متغیری که c به آن اشاره می‌کند، با نام مستعار k در دسترس خواهد بود، دستور خط سوم تقریباً معادل با int& k = x است، زیرا c به x اشاره می‌کند و c* یعنی مقدار متغیری که c به آن اشاره می‌کند که همان مقدار متغیر x خواهد بود. اما چون k از نوع reference است، پس مقدار x در آن کپی نمی‌شود، بلکه k به عنوان یک نام مستعار برای متغیر x در نظر گرفته می‌شود (مقدار x و k مشترک و دقیقاً یکی است).

پس برای reference کردن مقدار بازگشتی تابع =operator باید اینطور نوشت:



car& car::operator=(car a){
s=a.s;
pow=a.pow;
return *this;
}
در اینجالت چون نوع بازگشتی بصورت reference تعریف شده (ارجاع به شیئ (متغیری) از نوع car)، پس مقدار this* کپی نمی‌شود، بلکه یک نام مستعار برای آن در نظر گرفته خواهد شد.