typedef برای این استفاده میشه که برای یک نوع خاص یک اسم متفاوت بزاریم .
نحوه استفاده :
typedef old_type_name new_type_name;
مثال :
typedef char* CPtr;
typedef int Node;
typedef std::vector<int> vec;
typedef std::vector<std::string> string_vector;
typedef std::pair<Node,Node> Edge;
//...
یکی از جاهایی که typedef استفاده میشه زمانی هستش که میخواهید یک container تو در تو استفاده کنید .
مثلا برای یک وکتور از مپ بدون typedef این جور کدی باید نوشت :
#include <string>
#include <iostream>
#include <vector>
#include <map>
int main()
{
std::vector<std::map<std::pair<int, int>, std::string>> data;
//por kardan
std::map<std::pair<int, int>, std::string> inner_data;
inner_data[std::make_pair(5, 2)] = "test1";
inner_data[std::make_pair(2, 2)] = "test2";
inner_data[std::make_pair(1, 4)] = "test3";
data.push_back(inner_data);
data.push_back(inner_data);
//baraye peymayesh :
for (std::vector<std::map<std::pair<int, int>, std::string>>::const_iterator it=data.begin();
it != data.end(); ++it){
const std::map<std::pair<int, int>, std::string>& element = *it;
for (std::map<std::pair<int, int>, std::string>::const_iterator inner_it = element.begin();
inner_it != element.end(); ++inner_it){
const std::pair<int,int>& p = inner_it->first;
const std::string& str = inner_it->second;
std::cout << p.first << " " << p.second << " " << str<<'\n';
}
}
return 0;
}
حالا فرض کنید این loop ها قرار باشه 10 جای دیگه هم نوشته بشن چقدر کد عجیبی میشه !
با typedef مشه تمام انواع رو یک اسم کوچکتر بهشون داد و کد رو تمیز تر و کوتاه تر نوشت .
همون کد قبلی اینبار با استفاده از typedef :
#include <string>
#include <iostream>
#include <vector>
#include <map>
typedef std::pair<int, int> Pair;
typedef std::map<Pair, std::string> Map;
typedef std::vector<Map> Container;
typedef Container::const_iterator Container_CIterator;
typedef Map::const_iterator Map_CIterator;
int main()
{
Container data;
//por kardan
Map inner_data;
inner_data[std::make_pair(5, 2)] = "test1";
inner_data[std::make_pair(2, 2)] = "test2";
inner_data[std::make_pair(1, 4)] = "test3";
data.push_back(inner_data);
data.push_back(inner_data);
//baraye peymayesh :
for (Container_CIterator it = data.begin();it != data.end(); ++it)
{
const Map& element = *it;
for (Map_CIterator inner_it = element.begin();
inner_it != element.end(); ++inner_it)
{
const Pair& p = inner_it->first;
const std::string& str = inner_it->second;
std::cout << p.first << " " << p.second << " " << str<<'\n';
}
}
return 0;
}
از typedef برای اشاره گر های به تابع هم میشه استفاده کرد
مثلا برای ساختن اشاره گر به تابع زیر :
int foo(int,int);
بجای
int(*bar)(int,int)=foo;
میشه به شکل زیر نوشت که خواناتر هم هست !
typedef int(*function_type)(int,int);
function_type bar=foo;
مثلا این رو ببینید :
struct T2 { T2(int){ } };
int (*(*name)(T2))(int);
کد بالا رو به این شکل هیچ کسی نمی تونه بفهمه چیه ولی وقتی با typedef استفاده می کنیم :
typedef int (*return_type) (int);
typedef return_type(*function_type) (T2);
function_type name;
مشخص میشه که داریم یک اشاره به تابع تعریف می کنیم که ورودیش یک شی از T2 هست و خروجیش یک اشاره گر به تابع که int ورودیش هست و int هم بر می گردونه .
داخل این لینک هم در مورد typedef توضیحاتی داده شده : typedef چیه ؟
using جایگزین typedef در c++11 :
در c++11 کلمه کلیدی جدیدی به اسم using اضافه شده که کار typedef رو میکنه using به این شکل کار می کنه :
using new_type_name=old_type_name;
using تفاوت خاصی با typedef نداره ولی تا حدی خوانا تر از typedef هست .
مثلا همون اشاره گر به تابع بالا رو میشه این شکلی تعریف کرد
struct T2{};
using return_type = int(*)(int);
using function_type = return_type(*)(T2);
function_type name;
یا مثال اول :
using Pair = std::pair<int, int>;
using Map = std::map<Pair, std::string>;
using Container = std::vector<Map>;
using Container_CIterator = Container::const_iterator;
using Map_CIterator = Map::const_iterator;
define برای نوشتن ثابت هایی استفاده میشه که زمان کامپایل کد جایگزین محل استفاده شدن میشن (macro ها )
نحوه استفاده از define به شکل زیر هست :
#define name value
برای مثال :
#define MAX_SIZE 1000
#define MAX_INT32 0x7fffffff
#define FALSE 0
#define abs(a) ((a)>0?(a):(-1*a)) //ghadr motlagh a bargasht dade mishe
کاری هم که define می کنه اینه که زمان کامپایل اسم ای که استفاده شده با مقدارش عوض میشه یعنی مثلا هر جای کد از MAX_SIZE استفاده کردید زمان کامپایل با مقدار متناظرش که این جا 1000 هست جابه جا میشه.
مثال :
#include <iostream>
#define MAX_SIZE 50
#define MAGIC_NUMBER 4
#define ZERO 0
#define STR "..."
#define abs(a) ((a)>0?(a):(-1*a)) //ghadr motlagh a bargasht dade mishe
int main()
{
for (int i = 0; i < MAX_SIZE; i++){
if (i%MAGIC_NUMBER == ZERO )
std::cout << i <<" "<<STR<<'\n';
}
std::cout << abs(-5)<<" "<<abs(7) << '\n';
//khat bala ba in jaygozin mishe
// std::cout<< ((-5)>0?(-5):(-1*-5)) << ((7)>0?(7):(-1*7));
//bad compile mishe
}
البته برای تعریف ثابت ها میشه از const هم استفاده کرد که مزیت هایی هم داره این لینک رو ببینید : const در برابر define
این لینک هم یک مثال خوب دیگه از استفاده از define داخلش هست : فواید استفاده از macro
تفاوت define با typedef :
در typedef برای یک نوع اسم جدیدی میزاریم که این اسم جدید با همون نوع زمان کامپایل جایگزین میشه .
define کاری که انجام میده صرفا جایگزینی متن هست و لزومی نداره که بر روی type ها استفاده بشه .(برای نمونه داخل مثال بالا برای عدد 1000 ثابت MAX_SIZE گذاشتیم )
یا بصورت واضح تر یعنی این که typedef برای تعریف نوع داده ها استفاده میشه . define برای تعریف ماکرو ها .
typedef قواعد scope و typechecking براش برقرار هستش ولی define خیر .
مثال 1 :
#define SIZE 1000 //dorost
typedef 100 SIZE //error
مثال 2 :
#define ptr char*
int main()
{
ptr a, b;
ptr c = b;//error !!
}
داخل مثال بالا بخاطر این که صرفا متن جایگزین میشه نوع a میشه *char ولی نوع b میشه char برای همین خط بعدی ارور داده میشه
ولی داخل مثال بعدی کد کار می کنه :
typedef char* ptr;
int main()
{
ptr a, b;
ptr c = b;//ok
}