فضاهای اسمی

cpp

فضاهای اسمی برای پياده سازی اجزای نرم افزاری و کتابخانه های جديد بدون ايجاد برخورد اسامی با اجزای موجود بکارگرفته می شوند. در اين صفحه علاوه بر شرح فضاهای اسمی به انواع کلاس های حافظه نيز اشاره شده است.

 

فضای اسمی

وقتی يک برنامه به اندازه معينی می رسد معمولا به چند قطعه شکسته می شود، هر تکه ممکن است توسط افراد يا گروه متفاوتی ساخته و تکميل شود. زبان C تنها يک مکان برای نگهداری اسامی کليه شناسه ها و توابع دارد. يعنی برنامه نويسان بايد درباره نامگذاری اسامی محتاط باشند تا برخوردی پيش نيايد.

++C مکانيسمی برای جلوگيری از اين تصادم دارد: فضای اسمی (namespace). هر مجموعه از تعاريف که در يک کتابخانه يا يک برنامه قرار دارند درون يک فضای اسمی مجزا جا می گيرند. اعلان اسامی مشابه در فضاهای اسمی متفاوت هيچ برخوردی پيش نمی آورد.

فضای اسمی ناحيه ای است که يک شناسه اضافی را به اسامی عناصر درون خود الحاق می کند. هر نام بدليل اضافه شدن شناسه فضای اسمی منحصر بفرد خواهد شد. بنابراين می توان اسامی مشابه در فضاهای اسمی متفاوت حتی در يک فايل داشت. مادامی که اسامی مشابه در فضاهای اسمی مجزا هستند مشکلی در برنامه بروز نمی کند.

کلمه کليدی namespace يک نام منحصربفرد را برای يک فضای اسمی تعريف می کند. شکل کلی تعريف فضای اسمی به صورت زير است:

namespace identifier
{
[ declaration-list ]
}

identifier شناسه فضای اسمی است که برای ارجاع به اعضای آن استفاده می شود. declaration-list اعضای فضای اسمی هستند که حتما بايد درون آکولاد محصور شوند. اعضا می تواند شامل اعلان متغير، تابع، اشيا و فضای اسمی باشد.

به نام هرکدام از اعضا شناسه فضای اسمی توسط عملگر حوزه (::) اضافه می شود.

مثال. دو متغير x در دو فضای اسمی. يکی one::x و ديگری two::x خواهد شد.


namespace one {
int x;
}
namespace two {
float x;
}
int main() {
one::x++;
}


نکته. شناسه فضای اسمی در واحدی که استفاده می شود بايد يکتا باشد.
نکته. اعلان فضاهای اسمی می توانند تودرتو باشند.
نکته. عملگر حوزه (::) که قبل از آن شناسه ای نباشد به ناحيه سراسری اشاره می کند.


مثال. فضای اسمی B درون A تعريف شده است.

int i;
namespace A {
int j;
namespace B {
int j, k;
}
}
int main() {
A::j++;        //A’s j
A::B::j++;   // B’s j
::i++;          // the global i
}


می توانيد از فضای اسمی بدون شناسه به عنوان راهی برای اعلان متغيرهای ايستای سراسری بهره ببريد. فضای اسمی بدون نام شکل کلی زير را دارد.

namespace { declaration-list }

که در حقيقت مثل اين است که به صورت زير تعريف شده باشد.

namespace unique { declaration-list }
using namespace unique;

برخلاف نواحی تعريفی ديگر تعريف يک فضای اسمی می تواند در چندين قسمت درون يک واحد (مانند فايل) تقسيم شود. البته اعضای يک فضای اسمی شناسه دار می توانند در خارج از آن تعريف شوند به شرطی که بعد از تعريف فضای اسمی قرار بگيرد.


مثال. تعريف اعضای فضای اسمی در دو قسمت.

namespace A { // declare namespace A variables
int i;
int j;
}
namespace A { // declare namespace A functions
void func(void);
int int_func(int i);
}

مثال. توابع f() و g() متعلق به فضای اسمی V هستند که خارج از ان تعريف شده اند.

namespace X { void f() { } }
namespace V {
void f();
}
void V::f() { }   // ok
void V::g() { }   // g() is not yet a member of V
namespace V {
void g();
}


راهنمای using

فضای اسمی ابزار ساده و سودمندی است اما حضورشان به اين معنی است که شما قبل نوشتن برنامه بايد مواظب باشيد. تنها کافی نيست فايل هدری را پيوست کنيد و توابع و اشيای آن را استفاده کنيد. برای مواجه نشدن با خطای کامپايلر هنگام ترجمه برنامه بايد کامپايلر را مطلع کنيد که می خواهيد از اعلانات درون فضای اسمی استفاده کنيد. چون کامپايلر نمی تواند داده هائی که دربرنامه اعلان کرده ايد را پيدا کند.

با کلمه کليدی using به کامپايلر می گوييد از اعلانات يا تعاريف کدام فضای اسمی می خواهيد استفاده کنيد.

راهنمای using اجازه می دهد اعضای فضای اسمی بدون ذکر شناسه فضای اسمی استفاده شوند. البته استفاده از شناسه برنامه را خواناتر می کند. اما راهنمای using راه کوتاهتری برای ارجاع به اعضای فضای اسمی را فراهم می کند.


مثال. استفاده از راهنمای using .

namespace A {
int i;   // A::i
int j;   // A::j
}
namespace B {
int i;   // B::i
}
using namespace A;
void h() {
i++;        // A::i++
B::i++;   // B::i++
j++;        // A::j++
}


نکته. اگر متغير محلی هم نام با متغير فضای اسمی باشد متغير فضای اسمی مخفی می شود.
نکته. داشتن يک متغير فضای اسمی همنام با متغير سراسری خطا دارد.
نکته. راهنمای using را در ابتدای متن برنامه قرار دهيد.


فضای اسمی std

کليه کتابخانه های استاندارد ++C درون يک فضای اسمی قرارداده شده اند که std نام دارد. ممکن است راهنمای زير را در خيلی از برنامه ها مشاهده کنيد. اين خط بيان می کند که می خواهيد کليه عناصر درون فضای اسمی std در اختيار قرار بگيرد.

using namespace std;

بين فضای اسمی و نحوه ضميمه کردن فايل هدر ارتباط وجود دارد. اگر فايل هدر را به شکل include# <iostream.h> با پسوند .h ضميمه کنيد به معنی دو خط زير خواهد بود:

#include <iostream>
using namespace std;

اگر پسوند .h صريحا ذکر نشود راهنمای using را بايد اضافه کنيد.


مثال. استفاده از cout.

#include <iostream>
int main() {
std::cout << “Hello “;
using namespace std;
cout << “World.” << endl;
}


کلاس های حافظه

کلاس حافظه (storage class) تعيين می کند چگونه حافظه به متغيرها توسط کامپايلر واگذار شود. فضای حافظه برای ذخيره متغيرها و توابع و طول عمر اين فضا در طول اجرای برنامه توسط کلاس حافظه مشخص می شود.

محل ذخيره و محدوده متغيرها بسته به محلی (که می تواند داخل يا خارج بدنه تابع باشد) دارد که تعريف می شوند. وقتی پيش فرض های ذخيره سازی شما را راضی نمی کنند می توانيد از کلاس های حافظه استفاده کنيد.

کلاس های حافظه در C و ++C عبارتند از:

auto •
register •
static •
extern •
typedef •
•mutable

auto

اگر کلمه کليدی auto را قبل از اعلان متغيری قرار دهيد صريحا نوع ذخيره سازی اتوماتيک (automatic storage) را برای متغير مدنظر گرفته ايد. متغيری که ذخيره سازی اتوماتيک دارد با خروج از بلاکی که در آن تعريف شده پاک می شود. حافظه زمان ورود به بلاک اختصاص و زمان خروج از آن آزاد می شود.


مثال. اعلان صريح يک متغير اتوماتيک.

auto int i;


دسترسی به متغير از طريق اسم آن است. بخشی از برنامه است که نام متغير در آن قابل رويت است ميدان يا حوزه (scope) ناميده می شود.

ميدان عمل متغيرهای اتوماتيک درون بلاکی است که در آن اعلان شده اند و خارج از آن قابل رويت نيستند. به همين دليل به آنها متغيرهای محلی نيز گفته می شود.

کلاس auto برای متغيرهای محلی و درون بلاک نوع پيش فرض است و نيازی به ذکر کلمه auto نيست.

نکته. کلاس auto را می توانيد برای متغيرهای درون يک بلاک يا پارامترهای تابع اعمال کنيد.
نکته. با اشاره گرها می شود به متغيرهای محلی از خارج بلاک دسترسی پيدا کرد.
نکته. اگر متغير اتوماتيک مقداردهی اوليه نشود مقدارش نامعلوم خواهد بود. اگر يک مقدار اوليه تعيين کنيد هر زمان که وارد بلاکی که متغير در آن تعريف شده شود مقدار به متغير تخصيص داده می شود.
نکته. اگر از دستور goto برای پرش به بلوکی استفاده کنيد متغيرهای اتوماتيک مقداردهی نمی شوند.
نکته. اگر متغيری درون تابع بازگشتی اعلان شود در هربار فراخوانی تابع حافظه ايجاد و مقداردهی می شود.

register

ثبات ها حافظه هائی درون خود CPU هستند که داده آنها می تواند به سرعت دسترسی شود. معمولا کامپايلر تعيين می کند چه زمانی چه داده ای بايد در ثبات ذخيره شود. با وجود اين کلاس register اين امکان را به برنامه نويس می دهد که به کامپايلر بگوييد در صورت امکان متغير اتوماتيکی را درون ثبات ذخيره کند.

کامپايلر مجبور به اجرای اين درخواست نيست زيرا اندازه و تعداد ثبات های موجود در سيستم محدود است و تعداد کمی از متغيرها می توانند حقيقتا در ثبات ها قرار گيرند. اگر کامپايلر ثباتی را اختصاص ندهد با متغيرثباتی مانند متغير اتوماتيک برخورد می کند.


مثال. اعلان متغير از کلاس ثبات.

register int var;


نکته. متغيرهای ثباتی نوعی متغير اتوماتيک محسوب می شوند.
نکته. متغيرهای ثبات بايد درون يک بلاک يا به صورت پارامتر تاب

 

 

 

 

منبع : پی سی کد