خوش آموز درخت تو گر بار دانش بگیرد، به زیر آوری چرخ نیلوفری را


آموزش زبان ++C : فایل های هدر (Header files)

آموزش زبان ++C : فایل های هدر (Header files)
نویسنده : امیر انصاری
فایل های هدر (Header files) و هدف آنها

سیستم یکپارچۀ سازمانی راهکار



همچنانکه برنامه ها بزرگتر و بزرگتر می شود (و دارای فایل های بیشتری می گردند)، استفاده از اعلامیه های پیشاپیش (forward declare) برای هر تابعی که در فایل های مختلف استفاده می کنید، به طور فزاینده ای خسته کننده و سخت می شود. آیا اگر بتوانید همه اعلامیه ها را در یک فایل قرار بدهید بهتر نیست؟

فایل های کد ++C (که با پسوند cpp شناسایی می شوند) تنها فایل هایی نیستند که در زبان ++C خواهید دید. نوع دیگری از فایل ها نیز هستند که به نام فایل های هدر (Header files) شناسایی می شوند، برخی اوقات به این فایل ها، فایل های include نیز گفته می شود. فایل های هدر (Header files) معمولاً دارای پسوند h. می باشند، اما برخی اوقات ممکن است آنها را با پسوند hpp و یا حتی بدون پسوند ببینید. هدف از فایل های هدر (Header files) اینست که اعلامیه ها (declarations) مربوط به سایر فایلها را در خود نگهداری و سازماندهی کنند.

استفاده از فایل های هدر موجود در کتابخانه کدهای استاندارد ++C


برنامه زیر را در نظر بگیرید :

#include "iostream"
int main()
{
std::cout << "Hello, world!" << std::endl;
return 0;
}

این برنامه با استفاده از cout متن “Hello, world!” را در صفحه چاپ می کند. با این حال، هرگز در این برنامه cout معرفی نشده است، پس کامپایلر چگونه می فهمد که cout چیست؟ پاسخ اینست که cout در فایل هدری با نام “iostream” معرفی شده است. هنگامی که ما با استفاده از دستور include از فایل هدر iostream استفاده می کنیم، در واقع تمامی محتویات فایل iostream را در داخل فایل خودمان کپی می کنیم. این مساله منجر می شود تا کلیه محتویات فایل هدر مربوطه در کد ما موجود و قابل استفاده باشد.

به خاطر داشته باشید که فایل های هدر معمولاً تنها دارای اعلامیه ها (declarations) می باشند. آنها چگونگی اجرای کدها را مشخص نمی کنند. بنابر این اگر cout فقط در فایل هدر iostream اعلام شود، که در واقع تعریف هم شده است. پیاده سازی مرتبط با cout نیز در کتابخانه استاندارد ++C قرار دارد، که در طی مرحله لینک شدن به برنامه شما اضافه می گردد.

آموزش زبان ++C : فایل های هدر (Header files)
در نظر بگیرید که اگر فایل هدر iostream در برنامه شما نباشد چه اتفاقی می افتاد. در آن صورت هر بار که می خواستید از std::cout استفاده کنید باید به صورت دستی تمامی اعلامیه های مرتبط با std::cout را در کدتان کپی می کردید تا بتوانید از آن استفاده نمایید! این مساله نیاز به این دارد که دقیقاً بدانید چه کدهایی به std::cout مرتبط می باشد و چه چیزهایی مرتبط نمی باشد. بنابراین خیلی ساده تر است که فقط از دستور زیر استفاده کنید :

#include "iostream"


فایل های هدر (Header files) خودتان را بنویسید


اکنون اجازه بدهید تا به مثالی که در درس های قبلی به آن پرداختیم، مجدداً مروری داشته باشیم. دو فایل با نامهای add.cpp و main.cpp داریم که محتویاتشان به شکل زیر می باشد.

add.cpp

int add(int x, int y)
{
return x + y;
}

main.cpp

#include "iostream"

int add(int x, int y); // forward declaration using function prototype

int main()
{
std::cout << "The sum of 3 and 4 is " << add(3, 4) << std::endl;

std::cin.get();
return 0;
}

در فایل main.cpp با استفاده از اعلامیه های پیشاپیش (forward declare) تابع add را اعلام کرده ایم تا کامپایلر بداند که تابع add چه می باشد. همانطور که قبلاً ذکر شد، استفاده از اعلامیه های پیشاپیش (forward declare) در تک تک فایل ها می تواند به سرعت تبدیل به یک کار خسته کنند گردد.

فایل های هدر (Header files) می توانند این بار را از روی دوش ما بردارند. شما می توانید یک فایل هدر را یکبار بنویسید و بارها و بارها با استفاده از دستور include آن را در فایل های دیگر استفاده کنید. این مساله همچنین به نگهداری و تغییرات برنامه نیز کمک می کند. به عنوان مثال اگر نیاز به تغییر دادن نمونه اولیه تابع (Function prototypes) باشد، شما کافی است تا این تغییر را در یک محل انجام بدهید و در تمامی برنامه شما اثرش منعکس خواهد شد.

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

قسمت اول فایل هدر، گارد هدر (header guard) نامیده می شود که در درس بعدی در مورد آن صحبت خواهیم کرد. گارد هدر (header guard) از include شدن بیش از یکبار یک فایل هدر در فایل های یکسان جلوگیری می کند.

قسمت دوم، محتویات واقعی فایل هدر می باشد، که در واقع باید شامل اعلامیه های مربوط به کلیه توابعی باشند که می خواهیم در فایل های دیگر قادر به دیدن آنها باشیم. از آنجا که پسوند فایل های هدر ما باید h. باشد، فایل هدر خود را add.h می نامیم.

add.h

// This is start of the header guard.  ADD_H can be any unique name.  By convention, we use the name of the header file.
#ifndef ADD_H
#define ADD_H

// This is the content of the .h file, which is where the declarations go
int add(int x, int y); // function prototype for add.h -- don't forget the semicolon!

// This is the end of the header guard
#endif

برای استفاده از این فایل هدر در فایل main.cpp لازم است تا فایل هدر را در آن include کنیم.

main.cpp

#include "iostream"
#include "add.h"

int main()
{
std::cout << "The sum of 3 and 4 is " << add(3, 4) << std::endl;

std::cin.get();
return 0;
}

هنگامیکه کامپایلر کد

#include "add.h"

را کامپایل می کند، محتویات فایل add.h را به داخل فایل جاری کپی می کند. از آنجا که فایل add.h ما دارای نمونه اولیه تابع (Function prototype) برای تابع add می باشد، این نمونه اولیه در کد ما گنجانده خواهد شد.

در نتیجه، برنامه ما به درستی کامپایل و همینطور لینک (link) می شود.

نکته : هنگامی که فایلی را include می کنید، کلیه محتویات فایل include شده در محل قرار گیری دستور include قرار می گیرد.

آموزش زبان ++C : فایل های هدر (Header files)

چرا iostream دارای پسوند h. نیست؟


ممکن است این سوال پیش بیاید که چرا فایل iostream (یا هر فایل دیگری در کتابخانه استاندارد ++C) دارای پسوند h. نمی باشد؟ پاسخ اینست که فایل iostream.h یک فایل متفاوت از فایل iostream بدون پسوند می باشد! برای توضیح این مساله لازم است تا یک تایخچه بسیار کوتاه از آن را ذکر کنیم.

وقتی که ++C برای اولین بار ایجاد شد، کلیه فایلهای موجود در کتابخانه استاندارد ++C پسوند h. داشتند. زندگی برقرار و خوب بود. نسخه های اصلی cout و cin در فایل iostream.h زندگی می کردند. وقتی که این زبان توسط کمیته ANSI استاندارد سازی شد، آنها تصمیم گرفتند تا همه توابع را به داخل فضای نامی std منتقل کنند (که البته ایده خیلی خوبی هم بود). با این حال، یک مشکل ایجاد می شد : اگر آنها همه توابع استاندارد ++C را به فضای نامی std منتقل می کردند، هیچ کدام از برنامه های قدیمی که با نسخه های قبلی ++C نوشته شده بودند، دیگر نمی توانستند کار کنند!

برای برطرف شدن این مشکل، و فراهم آوردن امکانی برای سازگاری با برنامه های قدیمی (backwards compatibility)، یک مجموعه از فایل های هدر جدید، دقیقاً با همان اسامی پیشین ایجاد شدند اما اینبار برای آنها پسوند h. قرار داده نشد. در این فایلهای هدر جدید که بدون پسوند h. هم می باشند، تمامی آن کارکردهای پیشین در داخل فضای نامی std قرار داده شدند. در این روش ضمن اینکه برنامه های قدیمی با iostream.h کار می کنند، برنامه های جدید نیز با iostream به درستی کار می کنند.

وقتی که یک فایل هدر را از کتابخانه استاندارد ++C در داخل برنامه خود استفاده می کنید، توجه داشته باشید که از نسخه بدون پسوند h. آن استفاده کنید. در غیر اینصورت شما از یک نسخه قدیمی و بدون پشتیبانی آن استفاده خواهید کرد.

علاوه بر این، بسیاری از کتابخانه های کد قدیمی که از زبان C به ارث برده شده بودند، هنوز در ++C مفید هستند. به این کتابخانه ها یک پیشوند c داده اند (به عنوان مثال stdlib.h به cstdlib تبدیل شده است). کارکردهای این توابع به یادگار مانده از زبان C نیز برای جلوگیری از تصادم اسامی (naming collisions) به داخل فضای نامی std منتقل شده اند.

با این حال، وقتی که فایل های هدر خودتان را می نویسید، باید به همه آنها پسوند h. بدهید، چرا که شما نمی خواهید فایل های هدرتان را در داخل فضای نامی std قرار بدهید.

قانون : همیشه از نسخه بدون پسوند h. کتابخانه های کد استفاده کنید. مگر اینکه برای آن کتابخانه نسخه بدون پسوند h. موجود نباشد. در اینصورت از نسخه دارای پسوند h. استفاده نمایید.

افزودن فایل های هدر از سایر دایرکتوری ها (directories)


یکی دیگر از پرسش های رایج اینست که چگونه فایل های هدر موجود در سایر دایرکتوری ها (مسیرها یا همان پوشه های موجود در کامپیوتر) را در فایل خود include کنیم.

یک روش بد برای انجام این کار اینست که از مسیرهای نسبی مانند مثال زیر استفاده کنیم.

#include "headers/myHeader.h"
#include "../moreHeaders/myOtherHeader.h"

دلیل بد بودن این روش اینست که مجبور خواهید شد تا ساختار دایرکتورهای خود را در کد نشان دهید. در این صورت اگر پوشه بندی فایلهای خود را تغییر بدهید، کدهای شما دیگر به درستی کار نخواهند کرد.

یک روش بهتر اینست که به کامپایلر یا IDE خود بگویید که شما یکسری فایل هدر در مسیر دیگری دارید، بنابراین اگر کامپایلر نتواند در مسیرهای پیش فرض آن فایل های هدر را بیابد به مسیرهای معرفی شده توسط شما مراجعه خواهد کرد. این کار به طور کلی با تنظیم include path یا search directory در تنظیمات پروژه در IDE شما صورت می پذیرد.

در ویژوال استودیو، روی پروژه خود در Solution Explorer راست کلیک کنید، و Properties را انتخاب کنید. سپس در تب VC++ Directories این کار را صورت بدهید. پوشه هایی را که فایل های هدر خود را در آنجا قرار داده اید در اینجا باید معرفی کنید.

نکته خوب در مورد این رویکرد اینست که اگر مجبور شدید تا ساختار پوشه های پروژه خود را تغییر بدهید، تنها کاری که باید انجام بدهید اینست که در تنظیمات پروژه خود یک بار مسیر را تغییر بدهید و دیگر نیاز نخواهید داشت تا تک تک کدهایتان را تغییر بدهید.

آیا میتوانم یک تابع و یا یک متغیر را در داخل فایل هدر قرار بدهم؟


شما نباید این کار را انجام بدهید، چرا که ممکن است موجب ایجاد خطا در لینکر (linker errors) شود. این موضوع را در درس header guards بیشتر خواهیم شکافت.

به طور کلی، در فایل های هدر، صرفاً اعلامیه ها (Declarations) را قرار بدهید.

بهترین شیوه استفاده از فایل های هدر


در ادامه چندین شیوه خوب برای استفاده از فایلهای هدر را ذکر کرده ایم :

  • همیشه از گارد هدر (header guards) استفاده کنید.
  • هیچ گاه متغیرها را درون فایل های هدر قرار ندهید. مگر اینکه بخواهید از ثابتها (constants) استفاده کنید. فایل های هدر را به طور کلی باید برای اعلامیه ها (Declarations) مورد استفاده قرار داد.
  • توابع را در فایل های هدر معرفی نکنید.
  • هر فایل هدر باید یک کار مخصوص را انجام بدهد، و تا حد امکان مستقل از سایر فایل های هدر باشد. به عنوان مثال شما ممکن است تمامی اعلامیه های مربوط به کارکردهای مربوط به A را در فایل A.h قرار بدهید و همینطور کلیه اعلامیه های مربوط به کارکردهای B را در فایل B.h قرار بدهید. در این صورت، اگر در جایی به کارکردهای A نیاز داشته باشید، کافیست تا تنها فایل هدر A.h را در آنجا include کنید.
  • اسامی فایل های هدر خود را مشابه فایل های کد خود معرفی کنید. به عنوان مثال فایل هدر grades.h را برای فایل کد grades.cpp ایجاد کنید.
  • سعی کنید تا حداقل فایل های هدر مورد نیاز را در داخل کدتان include کنید. تنها فایل های ضروری را include کنید.
  • فایل های cpp را include نکنید.


آموزش قبلی : آموزش زبان ++C : برخورد نامها و فضای نامی std

آموزش بعدی : آموزش زبان ++C : مروری بر پیش پردازنده ها (preprocessor)



نمایش دیدگاه ها (4 دیدگاه)

دیدگاه خود را ثبت کنید:

انتخاب تصویر ویرایش حذف
توجه! حداکثر حجم مجاز برای تصویر 500 کیلوبایت می باشد.