#بیشتر_بدانید :
struct S1 {
bool a;
int b;
char c[100];
};
struct S2 {
char c[100];
int b;
bool a;
};
سرعت تغییر/دسترسی متغیر عضو هر شی از نوع S1 از هرشی از نوع S2 بیشتر است
struct S1 {
bool a;
int b;
char c[100];
};
struct S2 {
char c[100];
int b;
bool a;
};
سرعت تغییر/دسترسی متغیر عضو هر شی از نوع S1 از هرشی از نوع S2 بیشتر است
#بیشتر_بدانید
در این پست قصد دارم یه چیزی به دانش کسانی که اطلاع ندارن اضافه کنم که شاید یه روزی یه جایی بدردشون بخوره
حتما دیگه همتون با فایل ها آشنایی دارید
fstream outfile("filename",ios::out|ios::binary)
شاید تا حالا سوال براتون پیش اومده باشه که ios::out|ios::binary چه شکلی کار میکنه
این بار این رو میخوام به کسایی که نمیدونن خیلی خلاصه یاد بدم
اول باینری:
باید با باینری و عمل گر هاش آشنایی داشته باشین وگرنه با دیدن این کد ها به چیزی پی نمی برین (پس برید یاد بگیرید)
یه مثال
5 = 00000101
خب حالا چرا از اینios::out|ios::binary به جای bool استفاده میشه
برای استفاده بهتر اگه مثلا تعداد bool های توی یه کلاستون بیش از سه چهارتا بود بهتره به جای اینکه bool های جدا تعریف کنین یا آرایه از bool ها تعریف کنین یه متغیر تعریف کنین و بیت هاش رو به عنوان یه bool در نظر بگیرید(دلیلش هم حافظه هست وگرنه اگه میخواین به همون روش عمل کنین | عمل کنین . اشکالی نداره😄)
اعداد ضرب در دو که برای دو دویی بدردمون میخوره
1 و2 و4 و8 و16 و32 و64 و128 و256 و 512 و1024 و2048 و4096 و 8192 و ...
که اعداد معادل فقط یه بیت 1 هستن
مثلا برای مثال پایین من یه متغیر char در نظر میگرم چون تعداد bool هایی که در نظر دارم کمتر از 7 تا هست
class MyClass
{
public:
char My_Class_Flags=0;
};
حالا چند تا فلگ براش در نظر میگیرم
small = بیت اول
medium = بیت دوم
big = بیت سوم
cold = بیت چهارم
hot = بیت پنجم
حالا بیایین کلاسی که با همین ها با استفاده از bool کار میکنه رو بهتون نشون بدم
class MyClass
{
public:
bool small,medium,big,cold,hot;
};
😕
بریم همون با فلگ کار کنیم مثلا بهش خاصیت cold , medium رو بصورت همزمان بهش بدیم
int main()
{
MyClass a;
a.My_Class_Flags|=2;
a.My_Class_Flags|=8;
if(a.My_Class_Flags&1)
cout«"It's Small!"«endl;
if(a.My_Class_Flags&2)
cout«"It's Medium!"«endl;
if(a.My_Class_Flags&4)
cout«"It's Big!"«endl;
if(a.My_Class_Flags&8)
cout«"It's Cold!"«endl;
if(a.My_Class_Flags&16)
cout«"It's Hot!"«endl;
return 0;
}
به همین راحتی
حالا بیایید کار رو یخورده آسون تر کنیم
میدونم همتون بهتر از من کار enum رو بلد هستید😀😉
حالا تنها کاری که باید انجام بدیم اینه که مقادیر رو به enum بدیم تا اسم داشته باشن و خوانایی کد بالاتر بره
مثلا این شکلی
enum MyClassFeature
{
small = 1,medium=2,big=4,cold =8,hot = 16
};
حالا بیایین کد قبلیمون رو قشنگترش کنیم😊
int main()
{
MyClass a;
a.My_Class_Flags|=MyClassFeature::medium;
a.My_Class_Flags|=MyClassFeature::cold;
if(a.My_Class_Flags&MyClassFeature::small)
cout«"It's Small!"«endl;
if(a.My_Class_Flags&MyClassFeature::medium)
cout«"It's Medium!"«endl;
if(a.My_Class_Flags&MyClassFeature::big)
cout«"It's Big!"«endl;
if(a.My_Class_Flags&MyClassFeature::cold)
cout«"It's Cold!"«endl;
if(a.My_Class_Flags&MyClassFeature::hot)
cout«"It's Hot!"«endl;
return 0;
}
به همین راحتی
حالا سوال پیش میاد ما باید همه ی اون عدد ها رو بلد باشیم
جواب مسلما نه هست
استفاده از اعداد در مبنای 16 بهتر هست و خب همه حرفه ای ها اون رو اینجور مواقع ترجیح میدن
این شکل صحیح ترش
enum MyClassFeature
{
small = 0x01,medium=0x02,big=0x04,cold =0x08,hot = 0x10
};
حالا میتونیم یه تابع هم تعریف کنیم برای چک کردن مثلا:
class MyClass
{
public:
char My_Class_Flags=0;
bool isit(MyClassFeature in)
{
return My_Class_Flags∈
}
};
حالا همون کدمون یخورده خوشگل ترش😜
int main()
{
MyClass a;
a.My_Class_Flags|=MyClassFeature::medium|MyClassFeature::cold;//مثل همون فایل
if(a.isit(MyClassFeature::small))
cout«"It's Small!"«endl;
if(a.isit(MyClassFeature::medium))
cout«"It's Medium!"«endl;
if(a.isit(MyClassFeature::big))
cout«"It's Big!"«endl;
if(a.isit(MyClassFeature::cold))
cout«"It's Cold!"«endl;
if(a.isit(MyClassFeature::hot))
cout«"It's Hot!"«endl;
return 0;
}
درست مثل iosشد
میتونین ویژگی های بیشتر هم کنارش بذارین و مقادیر مثال رو به دلخواه خودتون تغییر بدید
در این پست قصد دارم یه چیزی به دانش کسانی که اطلاع ندارن اضافه کنم که شاید یه روزی یه جایی بدردشون بخوره
حتما دیگه همتون با فایل ها آشنایی دارید
fstream outfile("filename",ios::out|ios::binary)
شاید تا حالا سوال براتون پیش اومده باشه که ios::out|ios::binary چه شکلی کار میکنه
این بار این رو میخوام به کسایی که نمیدونن خیلی خلاصه یاد بدم
اول باینری:
باید با باینری و عمل گر هاش آشنایی داشته باشین وگرنه با دیدن این کد ها به چیزی پی نمی برین (پس برید یاد بگیرید)
یه مثال
5 = 00000101
خب حالا چرا از اینios::out|ios::binary به جای bool استفاده میشه
برای استفاده بهتر اگه مثلا تعداد bool های توی یه کلاستون بیش از سه چهارتا بود بهتره به جای اینکه bool های جدا تعریف کنین یا آرایه از bool ها تعریف کنین یه متغیر تعریف کنین و بیت هاش رو به عنوان یه bool در نظر بگیرید(دلیلش هم حافظه هست وگرنه اگه میخواین به همون روش عمل کنین | عمل کنین . اشکالی نداره😄)
اعداد ضرب در دو که برای دو دویی بدردمون میخوره
1 و2 و4 و8 و16 و32 و64 و128 و256 و 512 و1024 و2048 و4096 و 8192 و ...
که اعداد معادل فقط یه بیت 1 هستن
مثلا برای مثال پایین من یه متغیر char در نظر میگرم چون تعداد bool هایی که در نظر دارم کمتر از 7 تا هست
class MyClass
{
public:
char My_Class_Flags=0;
};
حالا چند تا فلگ براش در نظر میگیرم
small = بیت اول
medium = بیت دوم
big = بیت سوم
cold = بیت چهارم
hot = بیت پنجم
حالا بیایین کلاسی که با همین ها با استفاده از bool کار میکنه رو بهتون نشون بدم
class MyClass
{
public:
bool small,medium,big,cold,hot;
};
😕
بریم همون با فلگ کار کنیم مثلا بهش خاصیت cold , medium رو بصورت همزمان بهش بدیم
int main()
{
MyClass a;
a.My_Class_Flags|=2;
a.My_Class_Flags|=8;
if(a.My_Class_Flags&1)
cout«"It's Small!"«endl;
if(a.My_Class_Flags&2)
cout«"It's Medium!"«endl;
if(a.My_Class_Flags&4)
cout«"It's Big!"«endl;
if(a.My_Class_Flags&8)
cout«"It's Cold!"«endl;
if(a.My_Class_Flags&16)
cout«"It's Hot!"«endl;
return 0;
}
به همین راحتی
حالا بیایید کار رو یخورده آسون تر کنیم
میدونم همتون بهتر از من کار enum رو بلد هستید😀😉
حالا تنها کاری که باید انجام بدیم اینه که مقادیر رو به enum بدیم تا اسم داشته باشن و خوانایی کد بالاتر بره
مثلا این شکلی
enum MyClassFeature
{
small = 1,medium=2,big=4,cold =8,hot = 16
};
حالا بیایین کد قبلیمون رو قشنگترش کنیم😊
int main()
{
MyClass a;
a.My_Class_Flags|=MyClassFeature::medium;
a.My_Class_Flags|=MyClassFeature::cold;
if(a.My_Class_Flags&MyClassFeature::small)
cout«"It's Small!"«endl;
if(a.My_Class_Flags&MyClassFeature::medium)
cout«"It's Medium!"«endl;
if(a.My_Class_Flags&MyClassFeature::big)
cout«"It's Big!"«endl;
if(a.My_Class_Flags&MyClassFeature::cold)
cout«"It's Cold!"«endl;
if(a.My_Class_Flags&MyClassFeature::hot)
cout«"It's Hot!"«endl;
return 0;
}
به همین راحتی
حالا سوال پیش میاد ما باید همه ی اون عدد ها رو بلد باشیم
جواب مسلما نه هست
استفاده از اعداد در مبنای 16 بهتر هست و خب همه حرفه ای ها اون رو اینجور مواقع ترجیح میدن
این شکل صحیح ترش
enum MyClassFeature
{
small = 0x01,medium=0x02,big=0x04,cold =0x08,hot = 0x10
};
حالا میتونیم یه تابع هم تعریف کنیم برای چک کردن مثلا:
class MyClass
{
public:
char My_Class_Flags=0;
bool isit(MyClassFeature in)
{
return My_Class_Flags∈
}
};
حالا همون کدمون یخورده خوشگل ترش😜
int main()
{
MyClass a;
a.My_Class_Flags|=MyClassFeature::medium|MyClassFeature::cold;//مثل همون فایل
if(a.isit(MyClassFeature::small))
cout«"It's Small!"«endl;
if(a.isit(MyClassFeature::medium))
cout«"It's Medium!"«endl;
if(a.isit(MyClassFeature::big))
cout«"It's Big!"«endl;
if(a.isit(MyClassFeature::cold))
cout«"It's Cold!"«endl;
if(a.isit(MyClassFeature::hot))
cout«"It's Hot!"«endl;
return 0;
}
درست مثل iosشد
میتونین ویژگی های بیشتر هم کنارش بذارین و مقادیر مثال رو به دلخواه خودتون تغییر بدید
#بیشتر_بدانید
در این پست قصد دارم یه چیزی به دانش کسانی که اطلاع ندارن اضافه کنم که شاید یه روزی یه جایی بدردشون بخوره
کدی به شکل زیر داریم:
int main()
{
MyArray myarray;
myarray.a0 = 10;
myarray.a[1] = 20;
cout«myarray.a[0]«endl«myarray.a1«endl;
myarray.a1=100;
myarray.a[0]=50;
cout«myarray.a[1]«endl«myarray.a0«endl;
return 0;
}
و خروجی
10
20
100
50
نکته اصلی در کد بالا اینه که a0 با a[0] هیچ فرقی نداره
دستکاری تو یکیش معادل دستکاری تو اون یکی هست
همینطور a1 با a[1]
یه روش:
struct MyArray{
int a[2];
int & a0 = a[0];
int &a1=a[1];
};
و یه روش دیگر با استفاده از union:
struct MyArray
{
union{
struct{int a0,a1;};
int a[2];
};
};
به همین راحتی اعضای آرایه و اعضای متغیر همه با هم از یک حافظه استفاده میکنن و نکته اصلی که من دنبالش بودم همین بود .(اشتراک اعضای یک آرایه با متغیر های مختلف)
در این پست قصد دارم یه چیزی به دانش کسانی که اطلاع ندارن اضافه کنم که شاید یه روزی یه جایی بدردشون بخوره
کدی به شکل زیر داریم:
int main()
{
MyArray myarray;
myarray.a0 = 10;
myarray.a[1] = 20;
cout«myarray.a[0]«endl«myarray.a1«endl;
myarray.a1=100;
myarray.a[0]=50;
cout«myarray.a[1]«endl«myarray.a0«endl;
return 0;
}
و خروجی
10
20
100
50
نکته اصلی در کد بالا اینه که a0 با a[0] هیچ فرقی نداره
دستکاری تو یکیش معادل دستکاری تو اون یکی هست
همینطور a1 با a[1]
یه روش:
struct MyArray{
int a[2];
int & a0 = a[0];
int &a1=a[1];
};
و یه روش دیگر با استفاده از union:
struct MyArray
{
union{
struct{int a0,a1;};
int a[2];
};
};
به همین راحتی اعضای آرایه و اعضای متغیر همه با هم از یک حافظه استفاده میکنن و نکته اصلی که من دنبالش بودم همین بود .(اشتراک اعضای یک آرایه با متغیر های مختلف)
#بیشتر_بدانید
در پست بالا یه چیزهایی گفتم که جایگزینشون کنید با bool ها در کلاس
و من میخوام با چندتا کد ساده قانعتون کنم چرا bool در این گونه مواقع جالب نیست و چرا بهتره از این روش استفاده کرد
class MyClassOptimized
{
public:
char My_Class_Flags=0;
};
class MyClassNonOptimized
{
public:
bool small,medium,big,cold,hot;
};
این کد دوم واقعا زباله محسوب میشه چرا؟
از طریق کد زیر پی میبریم
cout«sizeof(MyClassNonOptimized)«endl;
cout«sizeof(MyClassOptimized)«endl;
خب حالا بگید که مقدار زیادی نیست ولی هست.😏
MyClassNonOptimized a[10000];
MyClassOptimized b[10000];
cout«sizeof(a)«endl;
cout«sizeof(b)«endl;
در پست بالا یه چیزهایی گفتم که جایگزینشون کنید با bool ها در کلاس
و من میخوام با چندتا کد ساده قانعتون کنم چرا bool در این گونه مواقع جالب نیست و چرا بهتره از این روش استفاده کرد
class MyClassOptimized
{
public:
char My_Class_Flags=0;
};
class MyClassNonOptimized
{
public:
bool small,medium,big,cold,hot;
};
این کد دوم واقعا زباله محسوب میشه چرا؟
از طریق کد زیر پی میبریم
cout«sizeof(MyClassNonOptimized)«endl;
cout«sizeof(MyClassOptimized)«endl;
خب حالا بگید که مقدار زیادی نیست ولی هست.😏
MyClassNonOptimized a[10000];
MyClassOptimized b[10000];
cout«sizeof(a)«endl;
cout«sizeof(b)«endl;
#بیشتر_بدانید
در این پست قصد دارم یه چیزی به دانش کسانی که اطلاع ندارن اضافه کنم که شاید یه روزی یه جایی بدردشون بخوره
دوتا تابع/متغیر داریم . یکی اسمش hello1 و دیگری hello2 که نوع هیچکدومشون مشخص نیست
با استفاده از سه روش زیر پی ببرید که کدوم تابعه و کدوم متغیر
این هم مثال های مثال همین طوری شانسی
float hello1(int a,float b)
{
}
int hello2;
روش اول:
خواص
generic programming
کد
template <typename T>
struct A{
const static bool isvar=true;
const static bool isfunc=false;
};
template <typename RT,typename ...Args>
struct A<RT(Args...)>{
const static bool isvar=false;
const static bool isfunc=true;
};
و
if(A<decltype(hello1)>::isfunc)
cout«"hello1 is function"«endl;
else if(A<decltype(hello1)>::isvar)
cout«"hello1 is var"«endl;
if(A<decltype(hello2)>::isfunc)
cout«"hello2 is function"«endl;
else if(A<decltype(hello2)>::isvar)
cout«"hello2 is var"«endl«endl;
روش دوم :
فرستادن به یک تابع اور لود شده
template<typename T>
bool isvar(T in)
{
return true;
}
template<typename RT,typename ...Args>
bool isvar(RT(*f)(Args...))
{
return false;
}
این تابع اگه متغیر بود صحیح بر میگردونه و تابع بود غلط
بر عکسش هم میشد
if(!isvar(hello1))
cout«"hello1 is function"«endl;
else
cout«"hello1 is var"«endl;
if(!isvar(hello2))
cout«"hello2 is function"«endl;
else
cout«"hello2 is var"«endl«endl;
و روش سوم:
تایپ آی دی
همه چی آماده هست ولی کارکردش تضمینی نیست
if(string(typeid(hello1).name()).find("F")==0)
cout«"hello1 is function"«endl;
else
cout«"hello1 is var"«endl;
if(string(typeid(hello2).name()).find("F")==0)
cout«"hello2 is function"«endl«endl;
else
cout«"hello2 is var"«endl;
در این پست قصد دارم یه چیزی به دانش کسانی که اطلاع ندارن اضافه کنم که شاید یه روزی یه جایی بدردشون بخوره
دوتا تابع/متغیر داریم . یکی اسمش hello1 و دیگری hello2 که نوع هیچکدومشون مشخص نیست
با استفاده از سه روش زیر پی ببرید که کدوم تابعه و کدوم متغیر
این هم مثال های مثال همین طوری شانسی
float hello1(int a,float b)
{
}
int hello2;
روش اول:
خواص
generic programming
کد
template <typename T>
struct A{
const static bool isvar=true;
const static bool isfunc=false;
};
template <typename RT,typename ...Args>
struct A<RT(Args...)>{
const static bool isvar=false;
const static bool isfunc=true;
};
و
if(A<decltype(hello1)>::isfunc)
cout«"hello1 is function"«endl;
else if(A<decltype(hello1)>::isvar)
cout«"hello1 is var"«endl;
if(A<decltype(hello2)>::isfunc)
cout«"hello2 is function"«endl;
else if(A<decltype(hello2)>::isvar)
cout«"hello2 is var"«endl«endl;
روش دوم :
فرستادن به یک تابع اور لود شده
template<typename T>
bool isvar(T in)
{
return true;
}
template<typename RT,typename ...Args>
bool isvar(RT(*f)(Args...))
{
return false;
}
این تابع اگه متغیر بود صحیح بر میگردونه و تابع بود غلط
بر عکسش هم میشد
if(!isvar(hello1))
cout«"hello1 is function"«endl;
else
cout«"hello1 is var"«endl;
if(!isvar(hello2))
cout«"hello2 is function"«endl;
else
cout«"hello2 is var"«endl«endl;
و روش سوم:
تایپ آی دی
همه چی آماده هست ولی کارکردش تضمینی نیست
if(string(typeid(hello1).name()).find("F")==0)
cout«"hello1 is function"«endl;
else
cout«"hello1 is var"«endl;
if(string(typeid(hello2).name()).find("F")==0)
cout«"hello2 is function"«endl«endl;
else
cout«"hello2 is var"«endl;
#آموزش ابتدایی دستورات پیش پردازنده و ماکرو ها
اول از همه اشاره کنم تمام پیش پردازنده ها هنگام کامپایل عمل میکنن نه هنگام اجرای برنامه
پس هیچوقت اون ها رو با متغیر های معمولی . توابع معمولی اشتباه نگیرید
تعدادی از خاصیت های اونها
کاهش حجم کدنویسی
استفاده به عنوان قالب
تعریف عمل کرد های مختلف
تعیین راحت تر رفتارهای مختلف با توجه به سیستم عامل یا کامپایلر
...
#include
خودتون از من هم بهتر بلدید
کارش اینه که محتویات یه فایل(هدر) رو به کدتون اضافه میکنه
مثال
اگر محتویات
header.h
این باشه
void helloworld();
و فایل
cpp
این باشه
#include “header.h”
int main(){
return 0;
}
مثل اینه که بنویسید
void helloworld();
int main(){
return 0;
}
عیننا کپی ش میکنه
#define نام
با استفاده از این میتونیم
یه ثابت داشته باشیم
که مقداری نداره
پس اگه هر جای کد اون رو بذارید مثل این میمونه چیزی اضافه نکردید
#define amir
و داخل کد
cout«”Hello!”«endl; amir
امیر رو اون انتها گذاشتم و انگار نه انگار
#define مقدار نام
این فرقش با بالایی اینه که هر جای کد بذارین
چیزی که جلوش هست رو مثل یه قالب میذاره همون جا
مثال:
#define pi 3.1415
cout«pi«endl;
حالا چه اتفاقی میفته
موقع کامپایل وقتی کامپایلر اون رو می بینه میفهمه که به جای پی باید مقدار جلوش رو جایگزین کنه
و این دقیقا مثل این میمونه که بنویسید
cout«3.1415«endl;
#define Fname(Args...) blo blo
ماکروهای شبیه تابع
باز هم میگم این کاملا فرق داره با توابع معمولی و هنگام کامپایل مثل قالب عمل میکنه
تنها کاری که میکنن اینه که با توجه به چیزهایی که بهشون میدید کارهای مختلف انجام میدن
یه مثال
#define MYMACRO() cout«
حالا کد
یادتون باشه این آرگومان نداره پس میتونید این کار رو مثل حالت بالا مثل عدد پی تعریف کنید
کد
MYMACRO() "Hello";
زیاد نترسید
هیچ چیز ترسناکی نیست
مثل حالت بالا کامپایلر محتویات جلوی اون ماکرو رو جایگزین میکنه
و دقیقا مثل اینه که بنویسید
cout«”Hello”«endl;
یه مثال دیگه
#define MYMACRO(A1) cout«A1«endl;
تو مثال بالا
A1
آرگومانش هست
تنها کاری که باید انجام میده اینه
شما بعدا هر چیزی رو و باز تاکید میکنم هر چیزی رو که به عنوان آرگومان بهش بدید عیننا اون رو داخل محتویات قرار میده
مثال کد
MYMACRO(25)
حتی لازم نیست سمی کالن بذارین
چون همون بالا یدونه براش تعریف کردیم
البته اگه بذارید هم اشکالی نداره چون سمی کالن های بیخودی پشت سرهم اثر ندارن
این کد مثل دقیقا مثل اینه که بنویسید
cout«25«endl;
حالا سایر دستورات
#ifdef
این دستور مشخص میکنه آیا بالای اون چیزی رو تعریف کردیم یا نه
یادتون نره حتما بالاش
چون کامپایلر از بالا به پایین کد رو کامپایل میکنه
ترتیب بالا و پایین خیلی مهمه
پایان این دستور وتمام حالت های شرطی با
#endif
مشخص میشه
یه مثال سطحی
#ifdef L
این قسمت رو به کدام اضافه کن
#endif
این یعنی اگر
L
تعریف شده بود
اون قسمت توی کد هامون موجود باشه
وگرنه موجود نباشه و کامپایل نشه
یه مثال
#ifdef L
void helloworld()
{
cout«"Hello World!"«endl;
}
#endif
سعی کنید تابع رو فراخوانی کنید
میبینید که نمیشه
فقط کافیه
L
رو بالاش تعریف کنین
مثلا
#define L
به همین راحتی مشخص میکنید داخل شرط به کدهاتون برای کامپایل اضافه شه.
دیگر ماکرو ها
#ifndef
یعنی اگر تعریف نشده بود اون قسمت تا
endif
کامپایل شه
#else
شبیه
else
هست یعنی اگر شرط برقرار بود که هیچ
درغیر اینصورت این قسمت به خروجی اضافه شه
پایانش هم با endif
مشخص میشه
مثال
#ifdef world
void helloworld()
{
cout«"Hello World!"«endl;
}
#else
void hellocity()
{
cout«"Hello city!"«endl;
}
#endif // city
این یعنی اگر
world
تعریف شده بود اون قسمت کامپایل شه
در غیر اینصورت
اون یکی قسمت کامپایل بشه
سعی کنید تعریف ها رو اضافه کنید و تست کنید
نکته اینه که
#else
برای سایر شروط هم عمل میکنه
#if
این یعنی اگر شرطی برقرار بود کامپایل شه
مثال
#if value==10
void helloworld()
{
cout«"Hello World!"«endl;
}
#endif // world
این یعنی اگه
value
تعریف شده بود و مقدار مساوی10 بود انوقت اون قسمت کامپایل شه
#elif
مثل
else if
میمونه
مثال
#if value==10
void helloworld()
{
cout«"Hello World!"«endl;
}
#elif value==20
void hellocity()
{
cout«"Hello city!"«endl;
}
#endif // world
این یعنی اگه مقدار برابر 10 بود اون قسمت اضافه شه در غیر اینصورت اگر مساوی بیست بود اون یکی قسمت اضافه شه
یه مقدار بدید و تست کنید حتما
#define value 10
مثلا
#error
این یعنی با استفاده از اون شرط ها میتونیم ارور درست کنیم
مثال
#if value!=10
#error value is not 10!
#endif // world
اول از همه اشاره کنم تمام پیش پردازنده ها هنگام کامپایل عمل میکنن نه هنگام اجرای برنامه
پس هیچوقت اون ها رو با متغیر های معمولی . توابع معمولی اشتباه نگیرید
تعدادی از خاصیت های اونها
کاهش حجم کدنویسی
استفاده به عنوان قالب
تعریف عمل کرد های مختلف
تعیین راحت تر رفتارهای مختلف با توجه به سیستم عامل یا کامپایلر
...
#include
خودتون از من هم بهتر بلدید
کارش اینه که محتویات یه فایل(هدر) رو به کدتون اضافه میکنه
مثال
اگر محتویات
header.h
این باشه
void helloworld();
و فایل
cpp
این باشه
#include “header.h”
int main(){
return 0;
}
مثل اینه که بنویسید
void helloworld();
int main(){
return 0;
}
عیننا کپی ش میکنه
#define نام
با استفاده از این میتونیم
یه ثابت داشته باشیم
که مقداری نداره
پس اگه هر جای کد اون رو بذارید مثل این میمونه چیزی اضافه نکردید
#define amir
و داخل کد
cout«”Hello!”«endl; amir
امیر رو اون انتها گذاشتم و انگار نه انگار
#define مقدار نام
این فرقش با بالایی اینه که هر جای کد بذارین
چیزی که جلوش هست رو مثل یه قالب میذاره همون جا
مثال:
#define pi 3.1415
cout«pi«endl;
حالا چه اتفاقی میفته
موقع کامپایل وقتی کامپایلر اون رو می بینه میفهمه که به جای پی باید مقدار جلوش رو جایگزین کنه
و این دقیقا مثل این میمونه که بنویسید
cout«3.1415«endl;
#define Fname(Args...) blo blo
ماکروهای شبیه تابع
باز هم میگم این کاملا فرق داره با توابع معمولی و هنگام کامپایل مثل قالب عمل میکنه
تنها کاری که میکنن اینه که با توجه به چیزهایی که بهشون میدید کارهای مختلف انجام میدن
یه مثال
#define MYMACRO() cout«
حالا کد
یادتون باشه این آرگومان نداره پس میتونید این کار رو مثل حالت بالا مثل عدد پی تعریف کنید
کد
MYMACRO() "Hello";
زیاد نترسید
هیچ چیز ترسناکی نیست
مثل حالت بالا کامپایلر محتویات جلوی اون ماکرو رو جایگزین میکنه
و دقیقا مثل اینه که بنویسید
cout«”Hello”«endl;
یه مثال دیگه
#define MYMACRO(A1) cout«A1«endl;
تو مثال بالا
A1
آرگومانش هست
تنها کاری که باید انجام میده اینه
شما بعدا هر چیزی رو و باز تاکید میکنم هر چیزی رو که به عنوان آرگومان بهش بدید عیننا اون رو داخل محتویات قرار میده
مثال کد
MYMACRO(25)
حتی لازم نیست سمی کالن بذارین
چون همون بالا یدونه براش تعریف کردیم
البته اگه بذارید هم اشکالی نداره چون سمی کالن های بیخودی پشت سرهم اثر ندارن
این کد مثل دقیقا مثل اینه که بنویسید
cout«25«endl;
حالا سایر دستورات
#ifdef
این دستور مشخص میکنه آیا بالای اون چیزی رو تعریف کردیم یا نه
یادتون نره حتما بالاش
چون کامپایلر از بالا به پایین کد رو کامپایل میکنه
ترتیب بالا و پایین خیلی مهمه
پایان این دستور وتمام حالت های شرطی با
#endif
مشخص میشه
یه مثال سطحی
#ifdef L
این قسمت رو به کدام اضافه کن
#endif
این یعنی اگر
L
تعریف شده بود
اون قسمت توی کد هامون موجود باشه
وگرنه موجود نباشه و کامپایل نشه
یه مثال
#ifdef L
void helloworld()
{
cout«"Hello World!"«endl;
}
#endif
سعی کنید تابع رو فراخوانی کنید
میبینید که نمیشه
فقط کافیه
L
رو بالاش تعریف کنین
مثلا
#define L
به همین راحتی مشخص میکنید داخل شرط به کدهاتون برای کامپایل اضافه شه.
دیگر ماکرو ها
#ifndef
یعنی اگر تعریف نشده بود اون قسمت تا
endif
کامپایل شه
#else
شبیه
else
هست یعنی اگر شرط برقرار بود که هیچ
درغیر اینصورت این قسمت به خروجی اضافه شه
پایانش هم با endif
مشخص میشه
مثال
#ifdef world
void helloworld()
{
cout«"Hello World!"«endl;
}
#else
void hellocity()
{
cout«"Hello city!"«endl;
}
#endif // city
این یعنی اگر
world
تعریف شده بود اون قسمت کامپایل شه
در غیر اینصورت
اون یکی قسمت کامپایل بشه
سعی کنید تعریف ها رو اضافه کنید و تست کنید
نکته اینه که
#else
برای سایر شروط هم عمل میکنه
#if
این یعنی اگر شرطی برقرار بود کامپایل شه
مثال
#if value==10
void helloworld()
{
cout«"Hello World!"«endl;
}
#endif // world
این یعنی اگه
value
تعریف شده بود و مقدار مساوی10 بود انوقت اون قسمت کامپایل شه
#elif
مثل
else if
میمونه
مثال
#if value==10
void helloworld()
{
cout«"Hello World!"«endl;
}
#elif value==20
void hellocity()
{
cout«"Hello city!"«endl;
}
#endif // world
این یعنی اگه مقدار برابر 10 بود اون قسمت اضافه شه در غیر اینصورت اگر مساوی بیست بود اون یکی قسمت اضافه شه
یه مقدار بدید و تست کنید حتما
#define value 10
مثلا
#error
این یعنی با استفاده از اون شرط ها میتونیم ارور درست کنیم
مثال
#if value!=10
#error value is not 10!
#endif // world
این یعنی اگر مقدار چیزی غیر از 10 باشه
ارور میده
اون چیزی که جلوی اروره پیامیه که نمایش داده میشه
#undef
از بین بردن یک تعریف که از قبل تعریف شده
مثال
#define L
#ifndef L
#error L is not defined
#endif // L
#undef L
#ifndef L
#error L is not defined
#endif // L
در ارور دوم ارور میده
چرا؟
چون
L
تعریفش رو پاک کردیم
اما بعدش اون رو از بین بردیم
همونطور که قبلا گفتم کد از بالا به پایین کامپایل میشه
یه مثال دیگه
#define L 10
#if L==10
void a(){cout«"hello a!"«endl;}
#endif // L
#undef L
#define L 20
#if L==20
void b(){cout«"hello b!"«endl;}
#endif // L
در مثال بالا هر دو کامپایل میشن
نکته
اون
undef
رو هم نذارید فرقی نمیکنه
ولی اگه
#define L 10
#if L==10
void a(){cout«"hello a!"«endl;}
#endif // L
#undef L
#ifndef L
void b(){cout«"hello b!"«endl;}
#endif // L
تو مثال بالا برای قسمت دوم وجودش مهمه
این یه آموزش ساده از تعدادی از دستورات پیش پردازنده بود
ارور میده
اون چیزی که جلوی اروره پیامیه که نمایش داده میشه
#undef
از بین بردن یک تعریف که از قبل تعریف شده
مثال
#define L
#ifndef L
#error L is not defined
#endif // L
#undef L
#ifndef L
#error L is not defined
#endif // L
در ارور دوم ارور میده
چرا؟
چون
L
تعریفش رو پاک کردیم
اما بعدش اون رو از بین بردیم
همونطور که قبلا گفتم کد از بالا به پایین کامپایل میشه
یه مثال دیگه
#define L 10
#if L==10
void a(){cout«"hello a!"«endl;}
#endif // L
#undef L
#define L 20
#if L==20
void b(){cout«"hello b!"«endl;}
#endif // L
در مثال بالا هر دو کامپایل میشن
نکته
اون
undef
رو هم نذارید فرقی نمیکنه
ولی اگه
#define L 10
#if L==10
void a(){cout«"hello a!"«endl;}
#endif // L
#undef L
#ifndef L
void b(){cout«"hello b!"«endl;}
#endif // L
تو مثال بالا برای قسمت دوم وجودش مهمه
این یه آموزش ساده از تعدادی از دستورات پیش پردازنده بود
using namespace Ali;
saybye();
{
using Ashkan::saybye;
saybye();
}
این یعنی داخل اون بلاک فقط از تابع در فضای نام امیر استفاده شه و میگیم که داخل اون بلاک اون استثنا هست
اگه ننویسیم تابع موجود در فضای نام علی اجرا میشه چون خبری از استثنا نیست
اما تفاوتش با
using
using Ashkan::saybye;
saybye();
{
using namespace Ali;
saybye();
}
در مثال بالا همیشه از
saybye
موجود در امیر استفاده میشه
چون بالاتر بهتون گفتم میشه گفت
using
جدی تر گرفته میشه
ولی میشه در بلاک های تو در تو
using
های متفاوت استفاده کرد
پس میشه نقضش کرد
using Ashkan::saybye;
saybye();
{
using Ali::saybye;
saybye();
}
با اینکار تونستیم نقضش کنیم
و حالیش کنیم رییس تو اون بلاک
saybye
علی هست
نه
saybye
امیر
درپایان تنها چیزی که مونده تا بهش اشاره کنم namespace
های تو در تو هست
namespace People
{
namespace Ashkan
{
void sayhello(){cout«"Hello Ashkan!"«endl;}
void saybye(){cout«"Good bye Ashkan!"«endl;}
}
namespace Ali
{
void sayhello(){cout«"Hello Ali!"«endl;}
void saybye(){cout«"Good bye Ali!"«endl;}
}
}
Amir
و
Ali
زیر مجموعه
People
هستن
برای استفاده ازشون حتما باید از نسخه داخلی استفاده کرد
using namespace People::Ashkan;
saybye();
برای دسترسی مستقیم
People::Ashkan::saybye();
این یه آموزش خیلی ابتدایی برای استفاده از
namespace
ها بود
saybye();
{
using Ashkan::saybye;
saybye();
}
این یعنی داخل اون بلاک فقط از تابع در فضای نام امیر استفاده شه و میگیم که داخل اون بلاک اون استثنا هست
اگه ننویسیم تابع موجود در فضای نام علی اجرا میشه چون خبری از استثنا نیست
اما تفاوتش با
using
using Ashkan::saybye;
saybye();
{
using namespace Ali;
saybye();
}
در مثال بالا همیشه از
saybye
موجود در امیر استفاده میشه
چون بالاتر بهتون گفتم میشه گفت
using
جدی تر گرفته میشه
ولی میشه در بلاک های تو در تو
using
های متفاوت استفاده کرد
پس میشه نقضش کرد
using Ashkan::saybye;
saybye();
{
using Ali::saybye;
saybye();
}
با اینکار تونستیم نقضش کنیم
و حالیش کنیم رییس تو اون بلاک
saybye
علی هست
نه
saybye
امیر
درپایان تنها چیزی که مونده تا بهش اشاره کنم namespace
های تو در تو هست
namespace People
{
namespace Ashkan
{
void sayhello(){cout«"Hello Ashkan!"«endl;}
void saybye(){cout«"Good bye Ashkan!"«endl;}
}
namespace Ali
{
void sayhello(){cout«"Hello Ali!"«endl;}
void saybye(){cout«"Good bye Ali!"«endl;}
}
}
Amir
و
Ali
زیر مجموعه
People
هستن
برای استفاده ازشون حتما باید از نسخه داخلی استفاده کرد
using namespace People::Ashkan;
saybye();
برای دسترسی مستقیم
People::Ashkan::saybye();
این یه آموزش خیلی ابتدایی برای استفاده از
namespace
ها بود
#بیشتر_بدانید
در این پست روشی خیلی ساده رو بیان میکنم که میتونید با استفاده از اون براحتی پی ببرید که آیا نوع دو تا متغیر با هم یکی هستن یا نه
برای اینکار فقط کافیه با استفاده از
template
ها یه اورلودینگ ساده انجام بدیم
این کدها با استاندارد سی پلاس پلاس 11 در جی سی سی تست شده هستن
تمپلیت دو نوع میگیره
اولی و دومی و داخل هر دو استراکت یه مقدار استاتیک داریم که مشخص میکنه آیا برابر هستن یانه
template<typename T1,typename T2>
struct issametype
{
const static bool value=0;
};
template<typename T>
struct issametype<T,T>
{
const static bool value=1;
};
یه مثال برای تست کد بالا:
int a;
int b;
double c;
double d;
cout«"a & b is:"«issametype<decltype(a),decltype(b)>::value«endl;
cout«"b & c is:"«issametype<decltype(b),decltype(c)>::value«endl;
cout«"c & d is:"«issametype<decltype(c),decltype(d)>::value«endl;
یک نشون دهنده اینه که یک نوع هستن ولی صفر یعنی نوعشون با هم فرق داره
وقتی که از
auto
استفاده میکنیم این خاصیت خیلی مفیده😄
int a;
auto b =a ;
double c;
auto d = c;
cout«"a & b is:"«issametype<decltype(a),decltype(b)>::value«endl;
cout«"b & c is:"«issametype<decltype(b),decltype(c)>::value«endl;
cout«"c & d is:"«issametype<decltype(c),decltype(d)>::value«endl;
یه باگ کوچولو
فرض کنید که یه نوع المنت آرایه با خود یه متغیر مقایسه شه اونوقت چی میشه
int a;
int b[10];
cout«"a & b is:"«issametype<decltype(a),decltype(b[0])>::value«endl;
میبینید که اشتباه میکنه چون نوع
b[0]
با نوع
a
هیچ فرقی ندارن
ولی خب یه ذره دارن😜
مشکل موقع فراخوانی عضو آرایه هست چون وقتی مینویسیم
b[0]
عضوش به صورت
int&
یعنی رفرنس برمیگرده نه
int
برای همینه که شما میتونید اعضای یه آرایه رو اصلاح کنید(البته میدونم میدونید😄)
برای رفع مشکل باز هم میتونیم بریم سراغ
template
ها و یه استراکت اور لود شده با تملیت هاش
بعد کافیه نوع ورودیش رو داخل به عنوان یه نوع دیگه تعریف کنیم
template<typename T>
struct removeref
{
typedef T type;
};
template<typename T>
struct removeref<T&>
{
typedef T type;
};
یه تست ازش بگیریم ببینیم چه طوره
این در حالت عادی
int b[10];
cout«issametype<decltype(b[0]),int&>::value«endl;
با استفاده از این استراکت میتونیم حالت رفرنس بودنش رو از بین ببریم
cout«issametype<removeref<decltype(b[0])>::type,int&>::value«endl;
دیدید دیگه
int&
نیست 😀
cout«issametype<removeref<decltype(b[0])>::type,int>::value«endl;
اینم مدرک👆🏼
😄
حالا میتونیم اون مثال باگ دار رو تعمیر کنیم
int a;
int b[10];
cout«"a & b is:"«issametype< removeref<decltype(a)>::type,removeref<decltype(b[0])>::type >::value «endl;
اوه یه ذره شلوغ شد
ولی الان دیگه بچه خوبی شده
دیگه باگ نیست😜
cout«"a & b is:"«
issametype<
removeref<decltype(a)>::type,
removeref<decltype(b[0])>::type
>::value
«endl;
موفق باشید
کد هاتون هم بی باگ😉
در این پست روشی خیلی ساده رو بیان میکنم که میتونید با استفاده از اون براحتی پی ببرید که آیا نوع دو تا متغیر با هم یکی هستن یا نه
برای اینکار فقط کافیه با استفاده از
template
ها یه اورلودینگ ساده انجام بدیم
این کدها با استاندارد سی پلاس پلاس 11 در جی سی سی تست شده هستن
تمپلیت دو نوع میگیره
اولی و دومی و داخل هر دو استراکت یه مقدار استاتیک داریم که مشخص میکنه آیا برابر هستن یانه
template<typename T1,typename T2>
struct issametype
{
const static bool value=0;
};
template<typename T>
struct issametype<T,T>
{
const static bool value=1;
};
یه مثال برای تست کد بالا:
int a;
int b;
double c;
double d;
cout«"a & b is:"«issametype<decltype(a),decltype(b)>::value«endl;
cout«"b & c is:"«issametype<decltype(b),decltype(c)>::value«endl;
cout«"c & d is:"«issametype<decltype(c),decltype(d)>::value«endl;
یک نشون دهنده اینه که یک نوع هستن ولی صفر یعنی نوعشون با هم فرق داره
وقتی که از
auto
استفاده میکنیم این خاصیت خیلی مفیده😄
int a;
auto b =a ;
double c;
auto d = c;
cout«"a & b is:"«issametype<decltype(a),decltype(b)>::value«endl;
cout«"b & c is:"«issametype<decltype(b),decltype(c)>::value«endl;
cout«"c & d is:"«issametype<decltype(c),decltype(d)>::value«endl;
یه باگ کوچولو
فرض کنید که یه نوع المنت آرایه با خود یه متغیر مقایسه شه اونوقت چی میشه
int a;
int b[10];
cout«"a & b is:"«issametype<decltype(a),decltype(b[0])>::value«endl;
میبینید که اشتباه میکنه چون نوع
b[0]
با نوع
a
هیچ فرقی ندارن
ولی خب یه ذره دارن😜
مشکل موقع فراخوانی عضو آرایه هست چون وقتی مینویسیم
b[0]
عضوش به صورت
int&
یعنی رفرنس برمیگرده نه
int
برای همینه که شما میتونید اعضای یه آرایه رو اصلاح کنید(البته میدونم میدونید😄)
برای رفع مشکل باز هم میتونیم بریم سراغ
template
ها و یه استراکت اور لود شده با تملیت هاش
بعد کافیه نوع ورودیش رو داخل به عنوان یه نوع دیگه تعریف کنیم
template<typename T>
struct removeref
{
typedef T type;
};
template<typename T>
struct removeref<T&>
{
typedef T type;
};
یه تست ازش بگیریم ببینیم چه طوره
این در حالت عادی
int b[10];
cout«issametype<decltype(b[0]),int&>::value«endl;
با استفاده از این استراکت میتونیم حالت رفرنس بودنش رو از بین ببریم
cout«issametype<removeref<decltype(b[0])>::type,int&>::value«endl;
دیدید دیگه
int&
نیست 😀
cout«issametype<removeref<decltype(b[0])>::type,int>::value«endl;
اینم مدرک👆🏼
😄
حالا میتونیم اون مثال باگ دار رو تعمیر کنیم
int a;
int b[10];
cout«"a & b is:"«issametype< removeref<decltype(a)>::type,removeref<decltype(b[0])>::type >::value «endl;
اوه یه ذره شلوغ شد
ولی الان دیگه بچه خوبی شده
دیگه باگ نیست😜
cout«"a & b is:"«
issametype<
removeref<decltype(a)>::type,
removeref<decltype(b[0])>::type
>::value
«endl;
موفق باشید
کد هاتون هم بی باگ😉
#بیشتر_بدانید
اهمیت هدر گارد ها
header guards
حتما همتون تا حالا هدر گاردهایی مثل بالا رو دیدید
اما اهمیتشون چیه؟
خیلی خلاصه جلوگیری از تعریف چندبار سهوی و ارور های ناخواسته
در مثال زیر خیلی ساده بهتون میگم چرا مفیدن
یه نکته » من برای جلوگیری از تکرار اسم هدر گارد ها از روشی استفاده میکنم که تقریبا اکثر برنامه نویس ها از اون روش استفاده میکنن
که
HEADERNAME
همون نام فایل هدر هست
حالا مثال:
محتویات فایل header2.h
محتویات فایل header1.h
محتویات فایل اصلی سی پلاس پلاس
میبینیدکه ارور نمیده و اجرا میشه
حالا
`
رو به فایل سی پلاس پلاس اضافه کنین
چه قبل اون header1.h بذارید چه بعدش ارور میده چون
دوبار تعریف میشه
حالا بیایید هدرگارد برای هر دو هدر تعریف کنید
محتویات جدید header2.h
محتویات جدید header1.h
و محتوای فایل اصلی
دیگه ارور نمیده
چند بار هم اینکلاد کنم خیالتون راحت شه
امیدوارم پی برده به باشید به اهمیتشون
نکته آخر: نوشته اشکان♻️
در بعضی کامپایلر ها لازم نیست
#pragma once
دقیقا همین کار رو انجام می
بعضی کامپایلر ها
موفق باشید
کدهاتون هم بی باگ
اهمیت هدر گارد ها
header guards
#ifndef HEADER_H
#define HEADER_H
#endif
حتما همتون تا حالا هدر گاردهایی مثل بالا رو دیدید
اما اهمیتشون چیه؟
خیلی خلاصه جلوگیری از تعریف چندبار سهوی و ارور های ناخواسته
در مثال زیر خیلی ساده بهتون میگم چرا مفیدن
یه نکته » من برای جلوگیری از تکرار اسم هدر گارد ها از روشی استفاده میکنم که تقریبا اکثر برنامه نویس ها از اون روش استفاده میکنن
#define HEADERNAME_H
که
HEADERNAME
همون نام فایل هدر هست
حالا مثال:
محتویات فایل header2.h
#include <iostream>
using namespace std;
void helloworld()
{cout<<"Hello World!"<<endl;
}
محتویات فایل header1.h
#include "header2.h"
void sayhello()
{helloworld();
}
محتویات فایل اصلی سی پلاس پلاس
#include "header1.h"
int main(){sayhello();
return 0;
}
میبینیدکه ارور نمیده و اجرا میشه
حالا
#include "header2.h"
`
رو به فایل سی پلاس پلاس اضافه کنین
#include "header1.h"
#include "header2.h"
int main(){sayhello();
return 0;
}
چه قبل اون header1.h بذارید چه بعدش ارور میده چون
`void helloworld()
دوبار تعریف میشه
حالا بیایید هدرگارد برای هر دو هدر تعریف کنید
محتویات جدید header2.h
#ifndef HEADER2_H
#define HEADER2_H
#include <iostream>
using namespace std;
void helloworld()
{cout<<"Hello World!"<<endl;
}
#endif
محتویات جدید header1.h
#ifndef HEADER1_H
#define HEADER1_H
#include "header2.h"
void sayhello()
{helloworld();
}
#endif
و محتوای فایل اصلی
#include "header1.h"
#include "header2.h"
int main(){sayhello();
return 0;
}
دیگه ارور نمیده
چند بار هم اینکلاد کنم خیالتون راحت شه
#include "header1.h"
#include "header2.h"
#include "header1.h"
#include "header2.h"
#include "header1.h"
#include "header2.h"
#include "header1.h"
#include "header2.h"
int main(){sayhello();
return 0;
}
امیدوارم پی برده به باشید به اهمیتشون
نکته آخر: نوشته اشکان♻️
در بعضی کامپایلر ها لازم نیست
این همه تایپکنیم
#pragma once
دقیقا همین کار رو انجام می
دهط
بازم میگم فق
بعضی کامپایلر ها
موفق باشید
کدهاتون هم بی باگ