"> اموزش c++ سازنده ها و فایل های سرآیند (قسمت دوازدهم)

اموزش c++ سازنده ها و فایل های سرآیند (قسمت دوازدهم)

تعریف سازنده

در خطوط ۱۷-۲۰ برنامه شکل ۷-۳ یک سازنده برای کلاس GradeBook تعریف شده است. توجه کنید که سازنده دارای نام مشابه همانند کلاس خود یعنی GradeBook است. یک سازنده توسط لیست پارامتری، داده مورد نیاز برای انجام وظیفه خود را مشخص می سازد. زمانیکه یک شی جدید ایجاد می کنید، این داده را در درون پرانتزهای قرار گرفته پس از نام شی قرار می دهید (همانند خطوط ۴۹-۵۰). خط ۱۷ بر این نکته دلالت دارد که سازنده کلاس GradeBook دارای یک پارامتر رشته‌ای بنام name است. دقت کنید که در خط ۱۷ نوع برگشتی مشخص نشده است، چرا که سازنده‌ها نمی توانند مقدار برگشت دهند (حتی void).

GradeBook

 

خط ۱۹ در بدنه سازنده مبادرت به ارسال پارامتر name سازنده به تابع عضو setCourseName می کند که مقداری به عضو داده courseName تخصیص می دهد. تابع عضو setCourseName (خطوط ۲۳-۲۶) فقط مبادرت به تخصیص پارامتر name خود به عضو داده courseName میکند، بنابر این ممکن است تعجب کنید که چرا زحمت فراخوانی setCourseName را در خط ۱۹ به خود داده‌ایم، در حالیکه سازنده بطور مشخص عملیات تخصیص courseName=name را انجام میدهد. در بخش ۱۰-۳، مبادرت به اصلاح setCourseName برای انجام عملیات اعتبارسنجی خواهیم کرد. در این بخش است که مزیت فراخوانی setCourseName از سازنده آشکار خواهد شد. توجه نمائید که در سازنده (خط ۱۷) و هم تابع setCourseName (خط ۲۳) از پارامتری بنام name استفاده شده است. میتوانید از اسامی پارامتری یکسان در توابع مختلف استفاده کنید چرا که پارامترها حالت محلی برای هر تابع دارند و سبب تداخل با دیگری نمیشوند.

تست کلاس GradeBook

خطوط ۴۶-۵۷ از برنامه شکل ۷-۳ حاوی تعریف تابع main است که مبادرت به تست کلاس GradeBook و اثبات مقداردهی اولیه شی GradeBook با استفاده از یک سازنده می کند. خط ۴۹ در تابع main اقدام به ایجاد و مقداردهی اولیه یک شی GradeBook بنام gradeBook1 میکند. زمانی که این خط از کد اجرا شود، سازنده GradeBook در خطوط ۱۷-۲۰ همراه با آرگومان “CS101 Introduction to C++ Programming” برای مقداردهی اولیه نام دوره gradeBook1 فراخوانی میشود، البته این فراخوانی بصورت ضمنی و توسط C++ صورت میگیرد. خط ۵۰ تکرار این فرآیند برای یک شی GradeBook بنام gradeBook2 است، این بار، آرگومان “CS102 Data Structures in C++” برای مقداردهی اولیه نام دوره gradeBook2 ارسال میشود. خطوط ۵۳-۵۴ از تابع عضو هر شی getCourseName برای بدست آوردن اسامی دوره و نمایش اینکه آنها در زمان ایجاد مقداردهی اولیه شده‌اند، استفاده کرده‌اند. خروجی برنامه تایید میکند که هر شی GradeBook از کپی عضو دادهcourseName متعلق بخود نگهداری کرده است.

دو روش برای تدارک دیدن یک سازنده پیش‌فرض برای یک کلاس

به هر سازنده‌ای که هیچ آرگومانی دریافت نکند، سازنده پیش‌فرض میگویند. یک کلاس به یکی از دو روش زیر سازنده پیش‌فرض بدست می آورد:

۱- کامپایلر بطور ضمنی یک سازنده پیش‌فرض برای کلاسی که سازنده‌ای برای آن تعریف نشده است، ایجاد می کند. چنین سازنده‌ای مبادرت به مقداردهی اولیه اعضای داده کلاس نمی کند، اما برای هر عضو داده که شی از کلاس دیگری هستند، سازنده پیش‌فرض را فراخوانی می کند [نکته: معمولاً یک متغیر مقداردهی نشده حاوی یک مقدار «اشغال» است (مثلاً یک متغیر int مقداردهی نشده می تواند حاوی ۸۵۸۹۹۳۴۶۰- باشد که این مقدار در بسیاری از برنامه‌ها برای این متغیر غلط می باشد).]

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

اگر برنامه‌نویس مبادرت به تعریف یک سازنده با آرگومان نماید، دیگر C++ بصورت ضمنی یک سازنده پیش‌فرض برای آن کلاس ایجاد نخواهد کرد. توجه نمائید که برای هر نسخه از کلاس GradeBook در برنامه‌های ۱-۳، ۳-۳ و ۵-۳ کامپایلر بصورت ضمنی یک سازنده پیش‌فرض تعریف کرده است.

 

افزودن سازنده به دیاگرام کلاس UML کلاس GradeBook

دیاگرام کلاس UML در شکل ۸-۳ مبادرت به مدل کردن کلاس GradeBook برنامه ۷-۳ کرده است، که دارای یک سازنده با پارامتر name از نوع رشته است (نوع String در UML). همانند عملیات‌ها، UML مبادرت به مدل‌سازی سازنده‌ها در بخش سوم کلاس در دیاگرام کلاس می‌کند. برای تمایز قائل شدن مابین یک سازنده از یک عملیات کلاس، UML مبادرت به قرار دادن کلمه “constructor” مابین گیومه (« و ») قبل از نام سازنده می کند. قرار دادن لیست سازنده کلاس قبل از دیگر عملیات‌ها در بخش سوم امری رایج است.

 

۸-۳  قرار دادن کلاس در یک فایل مجزا برای استفاده مجدد

تا آنجا که از منظر برنامه‌نویسی نیاز داشته باشیم به توسعه کلاس GradeBook ادامه خواهیم داد، از اینرو اجازه دهید تا وارد برخی از مباحث مهندسی نرم‌افزار شویم. یکی از مزایای تعریف دقیق یک کلاس در این است که به هنگام بسته (package) کردن صحیح، کلاس‌های ما میتوانند توسط سایر برنامه‌نویسان در سرتاسر جهان بکار گرفته شوند (استفاده مجدد). برای مثال، کتابخانه استاندارد C++ دارای نوع string است که میتوانیم از آن در هر برنامه C++ استفاده کنیم (استفاده مجدد). البته این کار را با وارد کردن فایل سرآیند <string> در برنامه انجام میدهیم.

متاسفانه، برنامه‌نویسانی که مایل به استفاده از کلاس GradeBook ما هستند، نمیتواند بسادگی و فقط با وارد کردن فایل از برنامه ۷-۳ به یک برنامه دیگر از آن استفاده کنند. همانطوری که در فصل دوم آموختید، تابع main اجرای هر برنامه‌ای را آغاز میکند و هر برنامه باید دارای یک تابع main باشد. اگر برنامه‌نویسان دیگر مبادرت به قرار دادن کد برنامه ۷-۳ نمایند، چمدان بزرگی بدست خواهند گرفت، تابع main ما، و برنامه آنها حاوی دو تابع main خواهد بود. زمانیکه مبادرت به کامپایل برنامه کنند، کامپایلر متوجه خطا خواهد شد، چرا که هر برنامه‌ای فقط میتواند یک تابع main داشته باشد. برای مثال، اگر مبادرت به کامپایل برنامه‌ای با دو تابع main در برنامه Mircrosoft Visual C++ .NET کنید، خطای زیر تولید میشود:

error C2084: function ‘int main(void)’ already has a body

هنگامی که کامپایلر سعی در کامپایل دومین تابع main میکند با خطا مواجه میشود. به همین ترتیب کامپایلر GNU C++ خطای زیر را تولید میکند:

redefinition of ‘int main()’

این خطاها بر این نکته دلالت دارند که برنامه در حال حاضر دارای یک تابع main است، بنابر این، قرار دادن main در همان فایل با تعریف کلاس از اینکه بتوان از کلاس در سایر برنامه‌ها استفاده مجدد کرد، ممانعت بعمل می‌آورد. در این بخش، به توضیح نحوه ایجاد کلاس GradeBook با هدف استفاده مجدد خواهیم پرداخت. روشی که در آن کلاس را در یک فایل مجزا از تابع main قرار می‌دهیم.

فایل‌های سرآیند

هر کدام یک از مثال‌های مطرح شده تا بدین مرحله متشکل از یک فایل .cpp بودند که بعنوان فایل کد-منبع نیز شناخته میشوند. این مثال‌ها حاوی تعریف کلاس GradeBook و یک تابع main بودند. به هنگام ایجاد یک برنامه شی گرای C++، تعریف کد منبع با قابلیت استفاده مجدد (همانند یک کلاس) در یک فایل که دارای پسوند فایل .h (فایل سرآیند) است، امری رایج می باشد. در برنامه‌ها از رهنمودهای پیش‌پردازنده #include برای وارد کردن فایل‌های سرآیند و برخوردار شدن از مزیت کامپونت‌های نرم‌افزاری با قابلیت استفاده مجدد کمک گرفته می شود، همانند نوع string تدارک دیده شده در کتابخانه استاندارد C++ و نوع‌های تعریف شده توسط کاربر مانند کلاس GradeBook.

در مثال بعدی، مبادرت به متمایز کردن کد برنامه از ۷-۳ با دو فایلGradeBook.h  برنامه شکل ۹-۳ و fig03_10.cpp برنامه شکل ۱۰-۳ میکنیم. همانطوری که در فایل سرآیند شکل ۹-۳ مشاهده میکنید، این فایل فقط حاوی تعریف کلاس GradeBook (خطوط ۱۱-۴۱) و خطوط ۳-۸ است که به کلاس GradeBook اجازه استفاده از endl ، cout و نوع string را میدهند. تابع main که از کلاس GradeBook استفاده میکند در فایل کد منبع fig03_10.cpp شکل ۱۰-۳ تعریف شده است، در خطوط ۱۰-۲۱. برای کمک به شما برای مهیا شدن برای کار با برنامه‌های بزرگ که در این کتاب و بازار کار با آنها مواجه خواهید شد، غالباً از یک فایل کد منبع متمایز یا جداگانه حاوی تابع main برای تست کلاس‌های خود استفاده میکنیم (به این برنامه، برنامه راه‌انداز یا درایور میگویند). بزودی با نحوه استفاده یک فایل کد منبع با main از تعریف کلاس موجود در یک فایل سرآیند در ایجاد شی های از یک کلاس آشنا خواهید شد.

cpp-ch3-91

cpp-ch3-92

شکل ۹-۳ | تعریف کلاس .GradeBook

وارد کردن فایل سرآیند که حاوی یک کلاس تعریف شده از سوی کاربر است

یک فایل سرآیند همانند GradeBook.h (برنامه شکل ۹-۳) نمی تواند برای شروع اجرای برنامه بکار گرفته شود، چرا که حاوی تابع main نمی باشد. اگر سعی در کامپایل و لینک خود GradeBook.h به منظور ایجاد یک برنامه اجرایی کنید، Microsoft Visual C++ .NET پیغام خطای لینکر را تولید خواهد کرد:

error LNK2019:unresolved external symbol _main referenced in

function _mainCRTStrartup

اگر در حال استفاده از GNU C++ بر روی لینوکس باشید، پیغام خطای لینکر بصورت زیر خواهد بود:

undefined reference to ‘main’

این خطا بر این نکته دلالت دارد که لینکر قادر به یافتن تابع main برنامه نشده است. برای تست کلاس GradeBook تعریف شده در شکل ۹-۳ بایستی یک فایل کد منبع جداگانه حاوی یک تابع main (همانند شکل ۱۰-۳) بنویسید که مبادرت به نمونه‌سازی و استفاده از شی های کلاس کند.

از بخش ۴-۳ بخاطر دارید که کامپایلر از مفهوم نوع‌های بنیادین همانند int مطلع است، اما با GradeBook آشنا نیست چرا که این نوع یک نوع تعریف شده از سوی کاربر (برنامه‌نویس) است. در واقع، کامپایلر حتی از کلاس‌های کتابخانه استاندارد C++ اطلاعی ندارد. برای کمک به کامپایلر برای اینکه متوجه نحوه استفاده از یک کلاس شود، بایستی بصورت صریح تعریف کلاس را در اختیار آن قرار دهیم. به همین دلیل است که برای مثال، به هنگام استفاده از نوع string، باید برنامه شامل فایل سرآیند <string> باشد. با انجام اینکار، کامپایلر قادر به تعیین میزان حافظه‌ای خواهد بود که باید برای هر شی از کلاس رزرو نماید و فراخوانی صحیح توابع عضو کلاس را تضمین میکند.

cpp-ch3-10

شکل ۱۰-۳ | وارد کردن کلاس GradeBook از فایل GradeBook.h برای استفاده در main.

برای ایجاد شی های gradeBook1 و gradeBook2 در خطوط ۱۳-۱۴ برنامه ۱۰-۳، باید کامپایلر از سایز یک شی GradeBook مطلع باشد. در حالیکه شی ها بصورت مفهومی حاوی اعضای داده و توابع عضو هستند، شی های C++ فقط حاوی داده می باشند. کامپایلر فقط یک کپی از توابع عضو کلاس ایجاد کرده و آن کپی را در میان سایر شی های کلاس به اشتراک می گذارد. البته هر شی نیازمند کپی متعلق بخود از اعضای داده کلاس است، چرا که محتویات آنها می توانند با سایر شی ها بسیار تفاوت داشته باشند (همانند دو شی مختلف BankAccount (حساب بانکی) که دو عضو داده متفاوت balance یعنی موجودی دارند). با این وجود، کد تابع عضو تغییر پذیر نیست، از اینرو میتواند در میان تمام شی های کلاس به اشتراک گذاشته شود. بنابر این، سایز یک شی وابسته به میزان فضای حافظه مورد نیاز برای ذخیره‌سازی عضوهای داده کلاس است. با وارد کردن GradeBook.h در خط ۷، به کامپایلر امکان دسترسی به اطلاعات مورد نیاز (شکل ۹-۳، خط ۴۰) برای تعیین سایز یک شی GradeBook و تعیین اینکه آیا شی های از آن کلاس بدرستی بکار گرفته شده‌اند یا خیر، داده میشود (در خطوط ۱۳-۱۴ و ۱۷-۱۸  شکل ۱۰-۳).

خط ۷ به پیش‌پردازنده C++ دستور جایگزین رهنمود با یک کپی از محتویات GradeBook.h (تعریف کلاس GradeBook) قبل از کامپایل برنامه را صادر میکند. زمانیکه فایل کد منبع fig03_10.cpp کامپایل میشود، حاوی تعریف کلاس GradeBook بوده (بدلیل #include)، و کامپایلر قادر به تعیین نحوه ایجاد شی های GradeBook و مشاهده فراخوانی صحیح توابع عضو خواهد بود. اکنون که تعریف کلاس در یک فایل سرآیند (بدون تابع main) قرار دارد، می توانیم سرآیند را در هر برنامه‌ای که نیاز به استفاده مجدد از کلاس GradeBook دارد وارد کنیم.

  • پسورد: www.mspsoft.com
مسعود شریفی پور

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

نوشته‌های مرتبط

دیدگاه‌ها

*
*

این سایت از اکیسمت برای کاهش هرزنامه استفاده می کند. بیاموزید که چگونه اطلاعات دیدگاه های شما پردازش می‌شوند.

    YES پاسخ

    THANKS
    VERY GOOD

    poria پاسخ

    salam
    chera akse .cpp bala nemyad