فضاهای اسمی

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;


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

 

 

 

 

منبع : پی سی کد