PDA

View Full Version : سوال: تعریف کلاس پشته



hercool
شنبه 15 آبان 1389, 12:43 عصر
سلم دوستان من یه سوال ارم که بهش نرسیدم ممنون میشم راهنمایی کنید
در تعریف کلاس پشته عناصر پشته را با size 5 نشون دادیم اما من می خوام بدونم که این متغییر چیه و چرا اینجوری به کار رفته با قرمز نشونش کردم

# define size 5
class stack {


}

hercool
شنبه 15 آبان 1389, 14:00 عصر
با سرچ زیاد پیداش کردم میگم کسی خواست بتونه استفاده کنه
در این نوع define عدد 5 رو داخل متغییر size قرار میده قبل از اینکه کلاس شروع به بار گزاری بشه
یک عمل پیش پردازنده است
اگر کسی توضیحی جامع تر و با جزئیات بیشتر داشت ممنون میشم اینجا بنویسه
با تشکر

sh4mid
شنبه 15 آبان 1389, 15:12 عصر
سلام
ببین تو C دستوراتی هست که بهش میگن Preprocessor
Compiler های خانواده C ، دو مرحله ای هستند،کار این پیش پردازنده ها اینه که تو مرحله اول ترجمه متن میاد و این دستورات رو تفسیر میکنه برای Compiler
معروف ترینش همون دستور آشنای include# هست که تو اول هر برنامه می نویسیم، این میاد به Compiler میگه برو از این فایل مقادیر،تعاریف و ... رو بخون
بعدیش دستور define# هست
مثلا فرض کن داشته باشیم
#define PI 3.14
حالا یک جا تو برنامه داشته باشیم
V=(4/3)*PI*r*r*r;
در مرحله اول ترجمه برنامه وقتی Compiler به همچین خطی میرسه به جای PI عبارت 3.14 رو جانشین میکنه
یعنی برنامت بعد از مرحله اول اینجوری می شود
V=(4/3)*3.14*r*r*r;

5 رو داخل متغییر size قرار میده
نه اصلا size متغیر نیست یک Token هست که تو مرحله اول ترجمه برنامه با عبارت 5 عوض میشود
(حالا اگر خواستی امتحان کن ، معمولا وقتی در Command line برنامه رو Compile کنی ، دستوری هست که این کار رو برات انجام میده ، یعنی Source برنامه رو بعد از مرحله اول بهت نشون میده(یادم میاد TC داشت))
کاربرد دیگه این پیش پردازنده ها در Compile شرطی هست که عبارتند از
#if, #ifdef, #ifndef, #else, #elif #endif
فرض کن اول برنامه نوشته باشیم
#define TEST
در اینجا عبارت TEST برای compiler تعزیف میشود(در مرحله اول)
حالا کمی پایین تر داشته باشیم

#ifdef TEST
printf("Test is defined");
#else
printf("Test is not defined");
#endif


این تکه کد تبدیل میشود به
printf("Test is defined");
که در مرحله بعد استفاده می شود

حالا این Compile شرطی به چه دردی می خورد؟به درد آزمایش برنامه و نوشتن برنامه های Cross platform
مثلا
#ifdef _WIN32 // _WIN32 is defined by all Windows 32 and 64 bit compilers, but not by others.
#include <windows.h>
#else
#include <unistd.h>
#endif

کاربرد دیگر پیش پردازنده ها تعریف macro هست
مثلا

#define RADTODEG(x) ((x) * 57.29578)

وقتی داشته باشی
y=RADTODEG(10);
میشه
y=((10)*57.29578);
البته الان دیگه توصیه نمیشه که از اینا استفاده کنی، چون خیلی راحت می تونه تولید Bug کنه،
مثلا نوع متغیر ها رو چک نمی کنه تو بالایی میشه به جای 10 گذاشت "ABC"، یک مدل دیگر هم خطا تولید میشه که کشفش سختتر هست
فرض کن داشته باشیم
#define RADTODEG(x) (x * 57.29578)
حالا یه جا بنویسیم
RADTODEG(a + b)
این تبدیل میشه به
(a + b * 57.29578)
در حالیکه منظور ما این بوده
((a + b) * 57.29578)
یعنی ما میخواستیم که اون دو تا متغیر اول با هم جمع بشن بعد تبدیل بشن به درجه ولی عدد دوم به درجه تبدیل میشود و بعدش با یک رادیان جمع میشه و نتیجه، سفینه ای سقوط می کند :لبخند::لبخند::لبخند:
بماند این مبحث خیلی زیاده بقیه اش رو برو اینجا (http://en.wikipedia.org/wiki/C_preprocessor)بخون

hercool
شنبه 15 آبان 1389, 16:41 عصر
اولش یه تشکر ویژه بخاطر توضیح شفاف و کاملت
اما چند تا موضوع
پس معنیش اینه که هر جا در برنامه size خواست ترجمه و محاسبه بشه 5 میاد و جانشینش میشه
درسته؟ که در اینجا یک محدود کننده یا بهتر بگم اندازه پشته ماست
این ماکرو که گفتی چه ویژگی داره ؟

این define چه ویژگی به برنامه میده
سرعت پردازش رو زیاد میکنه ؟امنیت برنامه رو بهتر می کنه ؟ کلا چه ویژگی داره ؟

sh4mid
شنبه 15 آبان 1389, 18:38 عصر
سلام

پس معنیش اینه که هر جا در برنامه size خواست ترجمه و محاسبه بشه 5 میاد و جانشینش میشه
بله برنامه هر جا size رو دید جاش 5 رو می گذارد(البته حالیش هست که مثلا "size" رو نکنه "5")

این ماکرو که گفتی چه ویژگی داره ؟
macro یه جورایی تابع هست، البته اگر بهش بشود گفت تابع ، کار برنامه نویسی رو راحت تر می کنه
ببین define میشه گفت دو تا کاربرد داره

تعریف macro
استفاده در compile شرطی

فرض کن برنامه ای نوشتی که یک Array رو داره شبیه سازی میکنه بعد می فهمی برنامت جواب درست نمی دهد ، می خواهی امتحانش کنی اول برنامت می نویسی
#define LOG
بعدش اون جایی که می خواهی برنامه رو چک کنی ، می نویسی
#ifedf LOG
//Log Dump Info in a file or Screen for Profile Code
clog<<"Array Size\t"<<Array.size<<endl;
clog<<"Array Items:\n";
for(int i=0;Array.siz;i++) clog<<"Itm"<<i<<":"<<Array[i]<<endl;
#endif
البته می تونی تو file هم بریزی ، حالا با مراجعه به file و یا دیدن خروجی می تونی بفهمی مشکل از کجا آب می خورد
(البته در عمل میتونی از DEBUG_ یا DEBUG استفاده کنی ، این دو تا macro در حالت debug تو visual studio تعریف شده و می تونی خروجی برنامه رو در حالت debug مشاهده کنی)
هونطور که قبلا هم گفتم می تونی مثلا شرط بگذاری یک تیکه از کدت رو برای Windows یا linux ، compile کنی

#ifdef WINDOWS
... /* Windows specific code */
#elif defined(UNIX)
... /* Unix specific code */
#else
#error "What's your operating system?"
#endif


سرعت پردازش رو زیاد میکنه ؟امنیت برنامه رو بهتر می کنه ؟ کلا چه ویژگی داره ؟

مسلما سرعت پردازش رو بیشتر می کند ، فرض کن داشته باشی

#define RADTODEG(x) ((x) * 57.29578)
float Rad2Deg(int x) return (x** 57.29578);

حالا جایی تو برنامت داشته باشی

for(int i=0;i<1000000000;i++)
{
y=RADTODEG(i);
//Some Code that modify y
}

که تبدیل میشه به

for(int i=0;i<1000000000;i++)
{
y=((i)*57.29578)
//Some Code that modify y
}

حالا کد بالایی رو مقایسه کن با کد زیر

for(int i=0;i<1000000000;i++)
{
y=Rad2Deg(i);
//Some Code that modify y
}

تو کدی که از تابع استفاده شده، تابع Rad2Deg ، به اندازه 1000000000 بار فراخوانی میشود ، یعنی هر دفعه باید Compiler مقادیر Heap و Stack و صد تا چیز دیگه رو تنظیم کنه بعد تابع رو فراخوانی کند که همه اینها overhead دارد ، در حالیکه با macro اصلا خبری از این overhead ها نیست
مثال

#include<iostream>
#include <ctime>
using namespace std;

#define RADTODEG(x) ((x) * 57.29578)
double Rad2Deg(long x) {return (x* 57.29578);}

int main()
{
double y=0.0,dif1=0.0,dif2=0.0;
time_t start,end;

time (&start);
for(long i=0;i<1000000000;i++)
{
y=RADTODEG(i);
y++;
}
time (&end);
dif1 = difftime (end,start);

time (&start);
for(long i=0;i<1000000000;i++)
{
y=Rad2Deg(i);
y++;
}
time (&end);
dif2 = difftime (end,start);

cout<<"Macro:"<<dif1<<endl;
cout<<"Func:"<<dif2<<endl;

system("pause");

return 0;
}

که منجر شد به جواب زیر



Macro:5
Func:87
Press any key to continue . . .

البته این زیاد دقیق نیست ولی بازم نمای خوبی به آدم می دهد(کلمه inline برای همین ساخته شد که یک جورایی کار macro رو برای تابع انجام میدهد، یعنی تابع رو فراخوانی نمیکنی بلکه کد تابع رو میاد اونجایی که مورد نیاز هست می نویسد)
یک سری کارها هم میشه با macro کرد که با تابع نمیشه مثلا

#define dumpme(x, fmt) printf("%s:%u: %s=" fmt, __FILE__, __LINE__, #x, x)

int some_function() {
int foo;
/* [a lot of complicated code goes here] */
dumpme(foo, "%d");
/* [more complicated code goes here] */
}

که نام یک عبارت رو به همراه مقدار اون برامون چاپ می کنه (نکته کلیدی استفاده از عملگر # که بهش میگن Stringizing Operator یا عملگر رشته ساز)

یا

#define MYCASE(item,id) \
case id: \
item##_##id = id;\
break

switch(x) {
MYCASE(widget,23);
}

حالا خط مثلا

MYCASE(widget,23);

تبدیل میشه به

case 23:
widget_23 = 23;
break;

با عملگر ## میشه دو تا عبارت رو به هم چسبوند(یه جورایی با این عملگرها میشه مدل درپیتی از template ها رو پیاده سازی کرد)

البته در استفاده از macro باید دقیق بود ،معایبشو بعدا می گم

sh4mid
شنبه 15 آبان 1389, 22:11 عصر
سلام
بریم سروقت معایبش
یک مدلشو قبلا گفتم


فرض کن داشته باشیم
#define RADTODEG(x) (x * 57.29578)

حالا یه جا بنویسیم
RADTODEG(a + b)

این تبدیل میشه به
(a + b * 57.29578)

در حالیکه منظور ما این بوده
((a + b) * 57.29578)

یعنی ما میخواستیم که اون دو تا متغیر اول با هم جمع بشن بعد تبدیل بشن به درجه ولی عدد دوم به درجه تبدیل میشود و بعدش با یک رادیان جمع میشه و نتیجه، سفینه ای سقوط می کند


به عنوان یک پیشنهاد همیشه دور Parameter های یک macro می تونید () بگذارید یعنی

#define MIN(a,b) ((a)>(b)?(b):(a))

حالا یک مدل دیگه
همین کد بالا رو در نظر بگیر به نظر درست میاد ، یعنی مثلا
MIN(a+b,c+d)
به نظر میاد مشکل آنچنانی نداره ، ولی دو تا مشکل داره

Compiler نوع a,b,c,d رو بررسی نمیکند
حالت پایین رو نگاه کن


#define MIN(a,b) ((a)>(b)?(b):(a))

فرض کن یک جا بنویسیم

MIN(++firstnum,secondnum)

این میشه

((++firstnum)>(secondnum)?(secondnum):(++firstnum))

firstnum دوبار افزایش پیدا کرده و باقی ماجرا

حالا یک روش بهترش

#define max(a,b) \
({ typeof (a) _a = (a); \
typeof (b) _b = (b); \
_a > _b ? _a : _b; })

که البته در حضرت GCC جواب میدهد :قهقهه:
یا
#define max(a, b, type, max) \
do { \
type _a = (a); \
type _b = (b); \
max = _a > _b ? _a : _b; \
} while (0)

البته وقتی می شود با template خیلی شیک مساله رو حل کرد مگر بیکاریم از این روش استفاده کنیم :متفکر::متفکر:

حالا فرض کن

#define CMDS \
a = b; \
c = d

if (var == 13)
CMDS;

که تبدیل میشه به

if (var == 13)
a = b;
c = d;

یعنی خط آخر همیشه اجرا میشه، حالا اگه داشته باشیم

if (var == 13)
CMDS;
else
return;

که میشه

if (var == 13)
a = b;
c = d;
else
return;

که کلا خطاست و میشه اینجوری اصلاحش کرد

#define CMDS a = b, c = d

if (var == 13)
CMDS;
else
return;

یا

#define CMDS \
do { \
a = b; \
c = d; \
} while (0)

یا دوباره در حضرت GCC :قهقهه: :قهقهه:

#define CMDS \
({ \
a = b; \
c = d; \
})

یعنی یا کل بی خیالش شو یا "به سراغ Macro اگر می روید () ، {} و بازبینی دقیق را فراموش نکن" :قهقهه: :قهقهه: :قهقهه: :قهقهه:


اینجا (http://en.wikibooks.org/wiki/C_Programming/Preprocessor) رو هم ببین بد نیست