PDA

View Full Version : سوال: کاربرد اشاره گر به تابع عضو کلاس



chikar
شنبه 16 خرداد 1394, 18:15 عصر
چه وجه تمایز و مزیتی اشاره گر به تابع عضو یک کلاس در فراخوانی و استفاده از یک تابع عضو کلاس نسبت به روش معمولی داره؟
بهتر بگم، کجا باید از این روش استفاده کرد و کجا باید یک تابع عضو کلاس رو معمولی فراخوانی کرد؟
اگر مثال بزنید ممنون می شم / مرسی

rahnema1
یک شنبه 17 خرداد 1394, 10:54 صبح
سلام
من پیشنهاد می کنم شما خودتون از توی نت یه مطلب مناسب گرد آوری کنید بذارید اینجا ما هم استفاده کنیم :)

chikar
یک شنبه 17 خرداد 1394, 23:14 عصر
سلام
من پیشنهاد می کنم شما خودتون از توی نت یه مطلب مناسب گرد آوری کنید بذارید اینجا ما هم استفاده کنیم :)

سلام بر آقای راهنمای گل، باشه من تا یه جایی جلو می رم، ولی یه جاهایی ابهاماتی برام وجود داره!

تا اونجا که من می دونم کلا از اشاره گر های به تابع برای مقادیر زمان اجرا مثل event ها بیشتر استفاده می شه، به طور غیر مستقیم از یک تابع استفاده می شه و مثلا از کابر یه اشاره گر به تابع گرفته می شه و بعد از یه رویداد مثل کلیک یک دکمه از طریق این اشاره گر فلان تابع اجرا می شه!


طرز استفاده اش هم به این شکل هست :


class p_to_mf
{
public:
int func(int x) {return ++x;}
};

void main() {

int (p_to_mf::*func)(int) = &p_to_mf::func;
p_to_mf pm;
std::cout << "pointer to memberfunction is: " << (pm.*func)(4);
}

output is : 5

حالا سوالات من :
1 - چرا وقتی یه اشاره گر به تابع ساخته می شه، مقدار true یا false بر می گرده؟ یعنی چی؟
2- event ها را چرا با این روش پیاده سازی می کنند؟

rahnema1
دوشنبه 18 خرداد 1394, 22:40 عصر
گل گلاب ببین
ابتدا در مورد اشاره گر به تابع مثالی می زنم مثلا تابع func را به این صورت می نویسیم:

int func(int a, float b)
{
std::cout<< "func"<<std::endl;
return 0;
}

نوع کلمه func از نوع تابع هست. در واقع نوع func میشه «تابعی که دو پارامتر int و float می گیره و int را بر می گردونه»
میشه آدرس تابعها را به دست آورد و در اشاره گری از نوع اون تابع ذخیره کرد
مثلا ما اگه می خواستیم آدرس یک متغیر int به دست بیاریم یک اشاره گر از نوع int تعریف کرده وآدرس یک int را داخل اون میذاشتیم

int a = 5;
int *b;
b = &a;

*/
/*
int a = 5;
int *b = &a;

که می تونیم به این صورت را هم بنویسیم:

int a = 5;
int (*b);
b = &a;



int a = 5;
int (*b) = &a;

که در اینجا تاکید می کنیم که b یک اشاره گر هست.
به همین ترتیب می تونیم آدرس یک تابع را به دست بیاریم
برای این کار ابتدا نوع برگشتی تابع را می نویسیم سپس یک پرانتز را باز و بسته می کنیم که داخل اون یک ستاره و سپس نام اشاره گر را می ذاریم و بعد یک پرانتز باز و بسته می کنیم که نوع پارامترهای ورودی داخلش هست
که می تونیم به این دو شکل بنویسیم:

int (*ptr_func) (int, float);
ptr_func = &func;



int (*ptr_func) (int, float) = &func;

بعد هم تابع را به صورت زیر صدا بزنیم:

ptr_func(3, 4.0f);
(*ptr_func)(3, 4.0f);

حالا نوع ptr_func میشه «اشاره گر به تابعی که دو پارامتر int و float می گیره و int را بر می گردونه»
در مورد تابع عضو اگه static باشه دقیقا مثل تابعهای معمولی نوشته می شه اما اگه عضو غیر استاتیک باشه به صورت زیر نوشته می شه

#include <iostream>
class A{
public:
static void func_static()
{
std::cout<< "static" << std::endl;
}
void func_non_static()
{
std::cout<< "non-static" << std::endl;
}
};
int main()
{
void (*p_static) ();
p_static = &A::func_static;
//void (*p_static) () = &A::func_static;
void (A::*p_nonstatic) ();
p_nonstatic = &A::func_non_static;
//void (A::*p_nonstatic) () = &A::func_non_static;
p_static();
(*p_static)();
(A().*p_nonstatic)();
A a;
(a.*p_nonstatic)();
}

در هر صورت همیشه نوع برگشتی اشاره گر تابع مطابق با تابع اصلی هست و اگه تابع اصلی مثلا نوع برگشتی اون bool باشه اشاره گر هم به صورت bool مشخص می کنیم
اما در مورد event ها
گاهی لازم می شه وقتی یک event اتفاق می افته ما یک کاری انجام بدیم
مثلا یک تابع می نویسیم به نام doEvent که اتفاقات مورد نظر ما در doEvent اجرا بشه
اما حالتی در نظر بگیرید که ما چند تا شیء مختلف داریم و می خواهیم اگر برای هر کدام event اتفاق افتاد یک کار جداگانه صورت بگیره
پس لازم می شه تابع doEvent را برای هر کدام باز نویسی کنیم
اما به جای این کار می تونیم تابع doEvent را جوری بنویسیم که یک تابع را بگیره و اون تابع را اجرا کنه
پس برای هر شیء یک تابع جداگانه می نویسیم و اشاره گر به تابع را به عنوان پارامتر می فرستیم به doEvent
در نتیجه همه اشیاء doEvent را صدا می زنند. اما با پارامترهای خاص خودشون
قبلا در مورد callback هم بحث شده بود. همچنین در مورد تابع qsort هم در یکی دو تا تاپیک توضیح داده بودم که چه طور از اشاره گر تابع در اون استفاده می شه به عنوان مثال شما باید بهش یک اشاره گر تابع معرفی کنیم که بین دو مقدار مقایسه انجام بده.
در واقع تابع qsort اومده یه چارچوب را فراهم کرده که بشه باهاش انواع داده مختلف را sort کرد. بدون اینکه لازم بشه خود تابع qsort دستکاری بشه
مثل این تاپیک: http://barnamenevis.org/showthread.php?463146

chikar
پنج شنبه 21 خرداد 1394, 19:06 عصر
مثل همیشه کامل و عالی بود مرسی
فقط یه سوال که فکر کنم منظورم رو درست متوجه نشدید:


در هر صورت همیشه نوع برگشتی اشاره گر تابع مطابق با تابع اصلی هست و اگه تابع اصلی مثلا نوع برگشتی اون bool باشه اشاره گر هم به صورت bool مشخص می کنیم


ما اگر آدرس یک تابع مستقل رو بخوایم، می تونیم اون رو بدست بیاریم، اما اگر تابع درون کلاس باشه، خروجی یک یا true بر می گرده!!! به این مثال توجه کنید

class A
{
public:
void A_func(){std::cout <<"A_func is run .. ";}
};

void func(){std::cout <<"func is run .. ";}


void main()
{

std::cout << "Address func is : " << &func << "\t Address A_func is: " << &A::A_func;

}
output is :
Address func is : 011C1310 Address A_func is: 1

در کد بالا آدرس تابع func به صورت هگزادسیمال در خروجی نمایش داده می شه، ولی برای تابع درون کلاس، آدرس این تابع به صورت مقدار یک چاپ می شه؟ اولا چرا؟ ثانیا آدرس تابع درون کلاس رو چطوری باید بدست آورد؟

در مورد callback هم یه سوال :
نقل قول از همون لینک فوق: مثلا در ویندوز شما میخواید هر یک ثانیه تابعتون فراخوانی بشه . اون تابع رو آدرسشو به سیستم عامل معرفی میکنین. سیستم عامل خودش هر یک ثانیه اونو فراخوانی کنه!!!
چطوری باید به سیستم عامل یک تابع رو معرفی کرد که خودش صرفا تابع مورد نظر رو اجرا کنه؟
بهتر بپرسم، ما اگر یک دکمه داشته باشیم، زمانی که قرار باشه یه event ای روی اون انجام بشه، مثلا روی اون کلیک بشه، آدرس تابع event مورد نظر (مثلا کلیک)به علاوه آدرس تابع اجرا شونده پس از انجام event(یعنی روی دکمه کلیک شد، این تابع اجرا شه)، حالا برنامه از کجا می فهمه که اصلا event انجام شده (مثلا کلیک شده) که بخواد این دو تا آدرس تابع رو(تابع event و تابعی که بعد از event باید کاری رو انجام بده) برای انجامشون به یه تابع اصلی دیگه بفرسته؟امیدوارم گیجتون نکرده باشم:لبخند:
مرسی

rahnema1
پنج شنبه 21 خرداد 1394, 22:57 عصر
واسه اینه که برای عملگر >> تعریف نشده که آدرس تابع را چاپ کنه
مثلا می تونیم سایز آدرس تابع و سایز آدرس تابع عضور را مشاهده کنیم که در سیستم 32 بیت برای من به ترتیب 4 و 8 نشون میده با استفاده از همین می شه مثلا آدرس را نشون داد

#include <iostream>
class A
{
public:
void A_func(){std::cout <<"A_func is run .. ";}
};

void func(){std::cout <<"func is run .. ";}

union Func_addr
{
unsigned long long address;
void (A::*func_ptr)();
};
int main()
{
std::cout<<"size of &A::A_func: "<<sizeof( &A::A_func) <<std::endl;
std::cout<<"size of &func: "<<sizeof( &func) <<std::endl;

Func_addr addr;
addr.func_ptr = &A::A_func;
std::cout<<"address of A::A_func: "<< addr.address << std::endl;
std::cout<<"address of func: "<< *reinterpret_cast<unsigned int*>(&func) <<std::endl;
}

در مورد کلیک هم فکر کنم شما می خواهید بدونید در سطوح پایین سخت افزار چه اتفاقی می افته. در اونجا بحث وقفه ها هست. اما سیستم عامل ها مثل ویندوز و لینوکس اجازه کار مستقیم با وقفه سخت افزاری را نمی دهند بلکه خودشون با وقفه ها کار می کنند وتابعهایی به نام api در اختیار ما قرار می دهند که مثلا بتونید با کلیک و event ها کار کنیم. اگه علاقه مند هستید می تونید در زمینه اینها مطالعه کنید. در سی پلاس پلاس ما دیگه کاری به وقفه ها نداریم بلکه از سطح api به بالا به قضیه نگاه می کنیم. مگه اینکه بخواهید سیستم عامل را دستکاری کنید یا در سطح پایین کار کنید
توی نت جستجو کنید مثلا با کلیک چه اتفاقی می افته و سوالاتی از این دست فکر کنم مطالب خوبی پیدا می کنید مثل:
https://www.udacity.com/course/viewer#!/c-ud189/l-636779583/m-639480909