View Full Version : سوال: this برای چه کاری هست و چه کابردی داره ؟
who are you
دوشنبه 14 اردیبهشت 1394, 00:23 صبح
سلام
من یه مشکل دارم توی یادگیری oop و فقط همین قسمت this و constructor و destructor هست وگرنه بقیه مفاهیم رو تاجایی که خوندم کاملا درک میکنم که چطور کار میکنن و برای چی هستن
فقط سر این سه مورد مخصوصا مخصوصا this مشکل دارم
خیلی ممنون میشم به صورت خیلی مبتدیانه توضیح بدید برام که کارش چیه برای چی هست و به چی اشاره میکنه
مثلا میگن this به خود ابچکت اشاره میکنه-خب به چه معنی هست ؟ که چی بشه؟
ممنون میشم تاجایی که میتونید طولانی و کامل و مبتدی توضیح بدید
دمتون گرم
chikar
دوشنبه 14 اردیبهشت 1394, 10:11 صبح
اشاره گر this چیست؟
اشاره گر this به شی جاری ، اشاره دارد، یعنی زمانی که یک نمونه از کلاس ساخته می شود، به طور ضمنی یک اشاره گر به آن شی یا نمونه کلاس فرستاده می شود، به عبارت دیگر آدرس نمونه کلاس همان آدرس this در کلاس است.
class myclass
{
int private_var;
public:
myclass() {
std::cout << " Address this is: " << this <<"\n";
}
};
void main()
{
myclass m1,m2;
std::cout << " Address m1 is: " << &m1 <<"\n" ;
std::cout << " Address m2 is: " << &m2 <<"\n" ;{
Address this is: 001DFCAC
Address this is: 001DFCB0
Address m1 is: 001DFCAC
Address m2 is: 001DFCB0
همانطور که در مثال فوق مشاهده می کنید، هر نمونه جدیدی که از کلاس ساخته می شود، دارای یک آدرس جدید this درون کلاس است، در اصل this همان آدرس شی جدید است که می توان از طریق آن توابع و متغیرهای عضو مختص این شی را مورد استفاده قرار داد.
نکته مهم : ار آنجا که در نوع استاتیک، مقادیر برای همه نمونه ها یکی است(بین اشیا به اشتراک گذاشته می شود)، در نتیجه نوع static ، اشاره گر this ندارد.
در بعضی از موارد استفاده از this ضروری است، و تنها راه حل است.
با استفاده از this می توان به متغیر ها توابع (اعضای داده ای کلاس از هر نوعی) دسترسی داشت. مثلا
class myclass
{
int private_var;
public:
myclass(int);
};
myclass::myclass(int x)
{
this->private_var = x;
}
برگرداندن مقدار توسط اشاره گر this :
در مثال زیر با توجه به نوع برگشتی int پس باید متد یک مقدار صحیح را برگرداند که به دو روش زیر ممکن است،.
int myclass::get_value()
{
return this->private_var; // return private_var;
// return *this; Error cannot convert from myclass to int
}
::in main ::
myclass m(2);
int value = m.get_value();
برگرداندن اشاره گر *this به تنهایی :
توجه کنید که نمی توان اشاره گر *this را به تنهایی برگرداند، فقط این اشاره گر زمانی به تنهایی برگشت داده می شود که نوع داده ای برگشتی از جنس کلاس باشد. مثال
class myclass
{
int private_var;
public:
myclass(int);
myclass get_value();
};
myclass::myclass(int x)
{
this->private_var = x;
std::cout << "Two constructor2 is run" <<"\n" << this->private_var;
}
myclass myclass::get_value()
{
//std::cout << "*this : " << *this; // Error
std::cout << " this->private_var " <<"\n" << this->private_var;
return *this; // return this->private_var;
}
void main()
{
myclass m = 7;
m.get_value();
//myclass m2 =m.get_value();
int m2 = m.get_value(); // Error canot convert from myclass to int
}
output is: Two constructor2 is run 7
مشابه مثال فوق فقط مقدار برگردانده شده از متد get_value را می توان درون یک شی از همین کلاس قرار داد.
در مثال فوق نمی توان مقدار m.get_value را درون یک متغیر از نوع int قرار داد و یا حتی با دستور cout چاپ کرد، و با خطای اینکه نمی توان نوع myclass را به int تبدیل کرد مواجه می شویم، توجه داشته باشید، ملاک، مقداری که برگردانده می شود نیست، ملاک نوع برگشتی تابع است که در اینجا myclass است و حتی مثلا اگر ما مقدار return 0; را هم بنویسیم باز اگر در مکان فراخوان به صورت زیر بنویسیم با خطا مواجه می شویم که نمی توان نوع myclass را به int تبدیل کرد.
myclass myclass::get_value()
{
return 0;
}
myclass m = 7;
int m2 =m.get_value();// Error cannot convert from myclass to int
//std::cout << "m2 is run" <<"\n" << m.get_value();// Error
کاربرد دیگر this :
می توان مقادیر را به صورت m.get_value().to_int یعنی پشت سر هم قرار داد، برای این کار باید مقدار برگشتی از تابع از جنس کلاس مورد نظر ما باشد، که می تواند یک نمونه از کلاس مد نظر ما باشد یا this همان کلاس باشد. مثلا
class myclass
{
int private_var;
public:
myclass(int);
myclass get_value(int g);
int to_int() {std::cout << "to_int is run: " <<"\n";return this->private_var;}
};
myclass::myclass(int x)
{
this->private_var = x;
std::cout << " constructor is run: " << this->private_var <<"\n";
}
myclass myclass::get_value(int g)
{
this->private_var += g;
return *this;
}
void main()
{
myclass m(100);
std::cout << " m get value main: " << m.get_value(4).to_int() <<"\n";
}
constructor is run: 100
to_int is run
m get value main: 104
در مثال فوق در تابع main برنامه متد m.get_value را به تنهایی نمی توان چاپ کرد و باید به نوع صحیح تبدیل شود، چون مقدار برگشتی از تابع get_value از جنس کلاس یعنی this است پس به تابع to_int هم که از جنس همین کلاس است می توان دسترسی داشت و در نتیجه تابع مورد استفاده قرار می گیرد.
chikar
دوشنبه 14 اردیبهشت 1394, 10:39 صبح
یادم هست یک بار سازنده رو براتون توضیح دادم، ولی فکر کنم خوب مطلب رو نرسوندم! امیدوارم این بار بهتر بگم.
سازنده کلاس (Constructor) :
یکی از بهترین و پرکاربردترین روش های استفاده از یک کلاس، استفاده از سازنده کلاس است.تابع سازنده یک تابع عضو است که در هنگام اعلان یک شی خود به خود فراخوانی می شود، وظیفه اصلی این تابع آماده کردن کلاس برای استفاده توسط یک شی و همچنین مقدار دهی اولیه اعضای نمونه کلاس و همچنین علاوه بر مقدار دهی می توان وظایف خاصی را مانند یک تابع معمولی به سازنده سپرد.
نکته: اگر کلاسی را در فایلی که تابع main قرار دارد، اعلان می کنید، آن کلاس باید قبل از تابع main نوشته شود.ولی مکان تعریف (پیاده سازی) مهم نیست.
چرا برای مقدار دهی اولیه به جای سازنده از متدی مثل set_values استفاده نمی کنیم:
دلیل این سوال را می توان به این صورت داد که سازنده را می توان با ایجاد فقط یک نمونه از کلاس فراخوانی کرد، می توان همزمان چندین سازنده داشت که هر کدام وظیفه خاصی را انجام دهند، سازنده، یک کلاس را برای استفاده یک شی فراهم میکند، و در کل استفاده از سازنده ها بسیار راحت تر، و با قابلیت تر هستند.
ویژگی های سازنده کلاس :
1- باید به عنوان اعضای عمومی کلاس اعلان و تعریف گردد.
2- هم نام با کلاس است.
3- هیچ نوع برگشتی حتی void یا اشاره گر this را هم بر نمی گرداند.
4- می توان چندین تابع سازنده داشت (فقط مشابه یک تابع معمولی باید تعداد و نوع پارارمتر های ورودی با هم تفاوت داشته باشد)
مثلا کلاس زیر رو در نظر بگیرید:
class myclass
{
int private_var;
public:
myclass() {std::cout << “First constructor1 is run" ;}
myclass(int);
// myclass(int,int,float = 0);
};
myclass::myclass(int x)
{
private_var = x;
std::cout << “two constructor2 is run" ;}
}
در مثال فوق ما دو تابع سازنده داریم، که یکی در خود کلاس تعریف (پیاده سازی) شده است و یکی خارج از کلاس، همانطور که مشاهده می کنید، عضو خصوصی کلاس که فقط درون کلاس قابل دسترسی است، توسط سازنده که عضوی از کلاس است مقدار دهی اولیه شده است.
زمان های فراخوانی سازنده :
با توجه به کلاس بالا حال توجه داشته باشید که حتما نیازی نیست، برای فراخوانی یک سازنده یک نمونه از کلاس(شی) ساخت، در بعضی موارد شما نیازی به نمونه کلاس ندارید و فقط می خواهید سازنده کلاس را اجرا کنید(یا به عبارتی با فراخوانی سازنده، از کل کلاس استفاده کنید) با توجه به مثال فوق نحوه فراخوانی سازنده ها را در تابع زیر ببینید.
void main()
{
myclass(); // First constructor1 is run
myclass(); // First constructor1 is run //اجرای سازنده برای بار دوم
myclass m; // First constructor1 is run //فقط برای سازنده بدون پارامتر اولیه
myclass m(); // بدون جواب
myclass m; m(); // Error
myclass(5); // two constructor2 is run
myclass m; //Error
در مثال فوق علت ، اگر سازنده بدون پارامتر ورودی نداشته باشیم، یا پارامتر ورودی سازنده دارای مقدار اولیه نباشد
myclass *m; //شی از جنس اشاره گر اجرای صحیح
myclass m=5; // two constructor2 is run
myclass m; m(8); // Error
myclass m(5); m=9; // two constructor2 is run 5 two constructor2 is run 9
myclass m = (4,6,9); // contrutor is run and x is: 9
در مثال بالا سازنده فقط یکبار اجرا می شودو آخرین مقدار یعنی 9 را به سازنده ارسال می کند، در ضمن مثال بالا به معنی سازنده ای با یک پارامتر ورودی است و اگر سازنده ای با سه پارامتر ورودی داشتیم و به شیوه بالا می نوشتیم با خطا مواجه می شدیم و باید به صورت زیر یعنی بدون عملگر انتساب می نوشتیم
myclass m(4,6,9);
myclass(4,6,9);
myclass m = (4,6,9); // Error
}
مقایسه سازنده ای بدون پارامتر ورودی با سازنده ای با پارامتر های ورودی پیش فرض:
توجه داشته باشید، اگر سازنده ای تعریف کنید که ده پارامتر وردی داشته باشد و برای پارامترهای ورودی آن مقدار پیش فرض تعیین کنید، و اگر همزمان یک سازنده بدون پارامتر ورودی تعریف کنید، کامپایلر دچار خطا می شود، که کدام سازنده منظور شماست و مانند این است که شما دو سازنده یکسان یا بدون پارامتر ورودی تعریف کرده اید.مثلا هر دو در زیر یکسان هستند
myclass(int *p = 0){}
myclass() {}
و نحوه فراخوانی هر دو نیز می تواند به این شکل باشد:
myclass m;
مخرب هم خیلی ساده هست، زمانی که کلاسی می سازید، شما فضایی رو از حافظه اشغال کردید، وقتی کارتون با کلاس تموم شد با استفاده از مخرب فضای اشغالی که کلاستون از حافظه گرفته رو بر می گردونید، اگر خودتون مخربی نسازید، کامپایلر یک مخرب پیش فرض می سازه و این کار رو می کنه، بر خلاف سازنده که چندین سازنده میشه، تعریف کرد، مخرب در هر کلاس فقط یکی است.
who are you
دوشنبه 14 اردیبهشت 1394, 10:42 صبح
بازم نشد :(
میشه به زبان خودمانی هم بگید کلی از اینها خوندم ولی باز درکش نمیکنم کاراییشو :(
نمیدونم چرا این یه جارو فقط گیر کردم :گریه:
chikar
دوشنبه 14 اردیبهشت 1394, 10:56 صبح
بازم نشد :(
میشه به زبان خودمانی هم بگید کلی از اینها خوندم ولی باز درکش نمیکنم کاراییشو :(
نمیدونم چرا این یه جارو فقط گیر کردم :گریه:
باور کن خودمونی تر از این دیگه بلد نیستم!:قهقهه: از حجم مطالبی که نوشتم نترسید،:متعجب: باور کنید ساده است:چشمک:
اگه می خواهید درکش کنید، باید با حوصله مطالب رو بخونید و تو کامپایلرتون هم تست کنید...
برای درک بهتر مفهوم کلاس، پیشنهاد می کنم با فریمورک Qt کار کنید و نحوه استفاده از کلاس ها رو ببینید(البته پیش نیازش C++ هست، ولی کار کنید باش می فهمید کلاس و سازنده و ... به چه درد می خوره)
لینک معرفی کیوت (http://barnamenevis.org/showthread.php?222357-%D9%85%D8%B9%D8%B1%D9%81%DB%8C-%D9%81%D8%B1%DB%8C%D9%85%D9%88%D8%B1%DA%A9-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%86%D9%88%DB%8C%D8%B3%DB%8C-%D8%A2%D8%B2%D8%A7%D8%AF-%D9%88-%D9%85%D8%B3%D8%AA%D9%82%D9%84-%D8%A7%D8%B2-%D9%BE%D9%84%D8%AA%D9%81%D8%B1%D9%85-Qt&p=987550&viewfull=1#post987550)
rahnema1
دوشنبه 14 اردیبهشت 1394, 22:41 عصر
سلام
مثلا یک کلاس داریم به نام «خانه»
از روی خانه یک شیء خانه درست می کنیم و می ریم داخل اون خونه ساکن می شیم
البته میشه خونه های دیگه هم برای افراد دیگه درست کرد که اونها هم به سر و سامون برسند
حالا می خواهیم شام بخوریم. به طور معمول مثلا تو خونه می پرسیم «امشب شام چیه؟»
چون وقتی ما در خانه خودمون قرار داریم منظورمون اینه که شام خونه ی «ما» امشب چیه و منظورمون این نیست که شام خونه های دیگه چیه
و بین جمله «امشب شام چیه؟» و «امشب شام خونه ما چیه؟» هیچ فرقی وجود نداره چون در هر دو صورت جواب می شه قرمه سبزی
یا اگه سر بی شام زمین بذاریم میشه یک رشته خالی! ""
این «ما» که در واقع یک ضمیر ملکی هست همون this هست
این حالت اوله که می گیم شام چیه
class Khane
{
public:
string sham;
string sham_chie()
{
return sham;
}
};
Khane my_khane;
my_khane.sham = "ghorme_sabzi";
cout << my_khane.sham_chie();
در حالت دوم میگیم شام خانه ما چیه
class Khane
{
public:
string sham;
string sham_chie()
{
return this->sham;
}
};
Khane my_khane;
my_khane.sham = "ghorme_sabzi";
cout << my_khane.sham_chie();
این دو حالت هیچ فرقی با هم نمی کنند
خب حالا شاید لازم بشه شام را از بیرون تهیه کنیم
یه تابع به نام تهیه شام ایجاد می کنیم و این تابع شام رااز بیرون می گیره و برای خونه ما اون شام را میاره
اگه به صورت زیر بنویسیم یه اشتباه ایجاد می شه
class Khane
{
public:
string sham;
void tahieh_sham(string sham)
{
sham = sham;
}
string sham_chie()
{
return this->sham;
}
};
در ایجاد در قسمت sham=sham مشخص نیست منظورمون از sham چیه. شامی هست که از بیرون گرفتیم یا شام خونه ما؟
اگه به صورت بالا بنویسیم متاسفانه هیچ شامی به ما تعلق پیدا نمی کنه چون همون شام بیرون را مساوی خودش قرار می دهیم!!
باید اینجور بنویسیم:
class Khane
{
public:
string sham;
void tahieh_sham(string sham)
{
this->sham = sham;
}
string sham_chie()
{
return this->sham;
}
};
یعنی شامی که از بیرون گرفته شده (sham) از طریق تابع به شام خونه ما یا this->sham تعلق بگیره
اینجا به خاطر اشتباهی که رخ میده حتما لازمه از this استفاده کنیم یا مثلا یه اسم دیگه واسه شام بیرون انتخاب کنیم:
class Khane
{
public:
string sham;
void tahieh_sham(string sham_biroon)
{
sham = sham_biroon;
}
string sham_chie()
{
return this->sham;
}
};
از کاربردهای دیگه اینه که بخواهیم خود شیء یا رفرنسی به اون را برگردونیم که فعلا همین قدر کافیه
در مورد سازنده هم در پست آخر تاپیک زیر در مورد لیزر یه چیزی گفته شده
http://barnamenevis.org/showthread.php?445414
لطفا اگه سوالی دارید دقیقا بگید کجا ابهام دارید
chikar
سه شنبه 15 اردیبهشت 1394, 00:09 صبح
سلام
مثلا یک کلاس داریم به نام «خانه»
از روی خانه یک شیء خانه درست می کنیم و می ریم داخل اون خونه ساکن می شیم
البته میشه خونه های دیگه هم برای افراد دیگه درست کرد که اونها هم به سر و سامون برسند...
خیلی جالب بود، خودمونی، خودمونی، که دوستمون می خواست، واقعا مرسی وقت می گذارید. :تشویق:
کاش خود شی یا رفرنس رو هم که برگشت داده میشه، مثال می زدید! مرسی
who are you
سه شنبه 15 اردیبهشت 1394, 02:04 صبح
اقا دم جفتتون گرم خیلی عالی قشنگ گرفتم this رو :تشویق: شام امشب مهمون من :لبخند:
درباره کنستراکتور هم دوباره پست اقای چیکار رو میخونم ببینم چی میشه انشالله اینم به خوبی برسم به هدف
فقط در مورد این this یه سوال داشتم که به زبان سی یا سی++ مربوط نیست اینجا بگم یا میشه پخ بدم ؟ :افسرده: درسته که مربوط به این زبان نیست ولی به همین توضیحی که دادین برمیگرده
rahnema1
سه شنبه 15 اردیبهشت 1394, 14:03 عصر
خیلی جالب بود، خودمونی، خودمونی، که دوستمون می خواست، واقعا مرسی وقت می گذارید. :تشویق:
کاش خود شی یا رفرنس رو هم که برگشت داده میشه، مثال می زدید! مرسی
مثال این یکی را اگه بشه خودتون زحمتش را بکشید ببنیم شما چه قصه ای سر هم می کنید :)
rahnema1
سه شنبه 15 اردیبهشت 1394, 14:04 عصر
اقا دم جفتتون گرم خیلی عالی قشنگ گرفتم this رو :تشویق: شام امشب مهمون من :لبخند:
درباره کنستراکتور هم دوباره پست اقای چیکار رو میخونم ببینم چی میشه انشالله اینم به خوبی برسم به هدف
فقط در مورد این this یه سوال داشتم که به زبان سی یا سی++ مربوط نیست اینجا بگم یا میشه پخ بدم ؟ :افسرده: درسته که مربوط به این زبان نیست ولی به همین توضیحی که دادین برمیگرده
فرقی نداره کجا بپرسید ولی اگه تو تالار بپرسید شاید مطلبی باشه که دوستان هم بتونند در بحث شرکت کنند
who are you
چهارشنبه 16 اردیبهشت 1394, 11:42 صبح
فرقی نداره کجا بپرسید ولی اگه تو تالار بپرسید شاید مطلبی باشه که دوستان هم بتونند در بحث شرکت کنند
ممنون
مثلا this رو توی مثالی که گفتین متوجه شدم ولی توی پایتون به این صورت هست
(def test(self,a,b
self.a = a
self.b = b
حالا اینجا این سوالو دارم که
self.a که همون کار this رو انجام میده درست؟
میشه بنویسیم self.pofak = a یا حتما باید self.a = a باشه?
و این که توی پرانتز چرا اولینشون self هست؟
توی سایت های انگلیسی توضیحش بود ولی چون اشنایی با این مباحث نداشتم خوب متوجه نشدم
rahnema1
چهارشنبه 16 اردیبهشت 1394, 19:54 عصر
ممنون
مثلا this رو توی مثالی که گفتین متوجه شدم ولی توی پایتون به این صورت هست
(def test(self,a,b
self.a = a
self.b = b
حالا اینجا این سوالو دارم که
self.a که همون کار this رو انجام میده درست؟
میشه بنویسیم self.pofak = a یا حتما باید self.a = a باشه?
و این که توی پرانتز چرا اولینشون self هست؟
توی سایت های انگلیسی توضیحش بود ولی چون اشنایی با این مباحث نداشتم خوب متوجه نشدم
شاید بهتر بود توی تالار python می پرسیدید
به عنوان مثال
class MyClass:
a = 5
def test(self,a,b):
self.a += b
self.b = a
self.pofak = b
self.pashmak = a+b
print(MyClass.a)
x = MyClass()
x.test(7 , 8)
print(x.a, x.b, MyClass.a, x.pashmak)
یک کلاس تعریف کردیم که دو خصیصه داره: یک عدد صحیح به نام a داره و یک تابع داره به نام test
اگه ما محتوای MyClass.a را چاپ کنیم مشکلی پیش نمیاد
اگه یک نمونه از این کلاس درست کنیم و به x اختصاص بدیم این دو خصیصه به x منتقل میشن
در ضمن میتونیم برای x یه سری خصیصه به نام b , pofak, و pashmak درست کنیم
self حتما لازمه برای متدهای نمونه کلاسها استفاده بشه. از یک طرف میشه باهاش به خصیصه های موجود در نمونه دسترسی پیدا کرد دلایل توجیه اینکه چرا باید در python اینجور نوشته بشه سلیقه کسی که این زبان را طراحی کرده اینجور بوده و توی لینک زیر توضیح داده
https://docs.python.org/3.1/faq/design.html
vBulletin® v4.2.5, Copyright ©2000-1404, Jelsoft Enterprises Ltd.