تعریف و تست کلاس GradeBook
مثال بعدی (برنامه شکل ۳-۳) تعریف مجددی از کلاس GradeBook (خطوط ۱۴-۲۳) با تابع عضو displayMessage است (خطوط ۱۸-۲۲) که نام دوره را بعنوان بخشی از رشته خوشآمدگویی چاپ می کند. تابع عضو جدید displayMessage مستلزم یک پارامتر است (courseName در خط ۱۸) که نشاندهنده نام دوره است.
کلاس GradeBook
قبل از اینکه به بررسی ویژگی های جدید کلاس GradeBook بپردازیم، اجازه دهید به نحوه استفاده از کلاس جدید در main نگاهی داشته باشیم (خطوط ۲۶-۴۰). در خط ۲۸ یک متغیر از نوع رشته (string) بنام nameOfCourse ایجاد شده است که از آن برای ذخیره کردن نام دوره وارد شده توسط کاربر استفاده خواهیم کرد. متغیر از نوع string نشاندهنده رشتهای از کاراکترها همانند “CS101 Introduction to C++ Programming” است. نوع string در واقع شی از کلاس string کتابخانه استاندارد C++ است. این کلاس در فایل سرآیند <string> تعریف شده و نام string همانند cout، متعلق به فضای نامی std است. برای اینکه خط ۲۸ قادر به کامپایل شدن باشد، خط ۹ حاوی سرآیند <string> است. دقت کنید که اعلان using در خط ۱۰ به ما اجازه می دهد تا به آسانی در خط ۲۸ از string بجای std::string استفاده کنیم. برای این لحظه، میتوانید در مورد متغیرهای string همانند متغیرهای از نوع دیگر همانند int فکر کنید. در بخش ۱۰-۳ با قابلیتهای string بیشتر آشنا خواهید شد.
خط ۲۹ یک شی از کلاس GradeBook بنام myGradeBook ایجاد میکند. خط ۳۲ به کاربر اعلان میکند که نام دوره را وارد سازد. خط ۳۳ مبادرت به خواندن نام دوره از ورودی کاربر کرده و آن را با استفاده از تابع کتابخانهای getline به متغیر nameOfCourse تخصیص میدهد. قبل از اینکه به توضیح این خط از کد بپردازیم، اجازه دهید تا توضیح دهیم چرا نمیتوانیم برای بدست آوردن نام دوره فقط بنویسیم
cin>>nameOfCourse;
در اجرای نمونه این برنامه، ما از نام دوره “CS101 Introduction to C++ Programming” استفاده کردهایم که حاوی چندین کلمه است. زمانیکه cin با عملگر استخراج به کار گرفته میشود، مبادرت به خواندن کاراکترها تا رسیدن به اولین کاراکتر white-space میکند. از اینرو فقط “CS101” توسط این عبارت خوانده میشود و برای خواندن مابقی نام دوره مجبور به عملیات ورودی اضافی خواهیم بود.
در این مثال، مایل هستیم تا کاربر نام کامل دوره را تایپ کرده و کلید Enter را برای تحویل آن به برنامه فشار دهد، و کل نام دوره در متغیر رشتهای nameOfCourse ذخیره گردد فراخوانی تابع getline(cin, nameOfCourse) در خط ۳۳، سبب میشود که کاراکترها (از جمله کاراکترهای فاصله که کلمات را از هم در ورودی جدا میکنند) از شی ورودی استاندارد جریان cin (صفحه کلید) تا رسیدن به کاراکتر خط جدید خوانده شده و در متغیر رشتهای nameOfCourse جای داده شده و کاراکتر خط جدید حذف میگردد. توجه نمائید زمانیکه کلید Enter فشرده میشود (در زمان تایپ ورودی)، یک خط جدید (newline) به جریان ورودی افزوده میشود. همچنین توجه کنید که فایل سرآیند <string> باید قرار داشته باشد تا بتوان از تابع getline استفاده کرد. نام این تابع متعلق به فضای نامی std است.
شکل ۳-۳ | تعریف کلاس GradeBook با تابع عضوی که پارامتر دریافت میکند.
خط ۳۸ تابع عضو displayMessage شی myGradeBook را فراخوانی میکند. متغیرnameOfCource موجود در درون پرانتزها آرگومانی است که به تابع displayMessage ارسال میشود، از اینروست که تابع میتواند وظیفه خود را به انجام رساند. مقدار متغیر nameOfCourse در main تبدیل به مقدار پارامتر courseName تابع عضو displayMessage در خط ۱۸ میشود. زمانیکه این برنامه اجرا شود، توجه نمائید که تابع عضو displayMessage به همراه پیغام خوشآمدگویی، نام دوره تایپ شده توسط کاربر را به نمایش درمی آورد.
آرگومانها و پارامترهای بیشتر
برای تصریح اینکه تابعی نیازمند داده برای انجام وظایف خویش است، اطلاعات اضافی را در لیست پارامتری تابع قرار میدهیم، لیستی که در درون پرانتزها قرار گرفته پس از نام تابع جای دارد. لیست پارامترها میتواند به هر تعداد پارامتر داشته باشد یا اصلاً پارامتری نداشته باشد (همانند پرانتزهای خالی در خط ۱۳ برنامه شکل ۱-۳) تا نشان دهد تابع نیاز به هیچ پارامتری ندارد. لیست پارامتری تابع عضو displayMessage به نحوی اعلان شده که تابع نیازمند یک پارامتر است (شکل ۳-۳، خط ۱۸). هر پارامتر باید دارای نوع و یک شناسه باشد. در این مورد، نوع string بوده و شناسه courseName است و نشان میدهد که تابع عضو displayMessage مستلزم یک رشته برای انجام وظیفه خویش است. بدنه تابع عضو از پارامتر courseName برای دسترسی به مقدار ارسالی به تابع در فراخوانی تابع (خط ۳۸ در main) استفاده میکند. خطوط ۲۰-۲۱ مقدار پارامتر courseName را بعنوان بخشی از پیغام خوشآمدگویی به نمایش در می آورد. توجه نمائید که نام متغیر پارامتری (خط ۱۸) می تواند همنام متغیر آرگومان (خط ۳۸) یا نام متفاوتی داشته باشد. در فصل ششم با دلایل اینکارها آشنا خواهید شد.
یک تابع می تواند دارای چندین پارامتر باشد، بشرطی که هر پارامتر از دیگری با یک ویرگول مجزا شده باشد (در مثال شکلهای ۴-۶ و ۵-۶ شاهد آنها خواهید بود). تعداد و ترتیب آرگومانها در یک تابع فراخوانی شده بایستی با تعداد و ترتیب لیست پارامترها در سرآیند تابع عضو فراخوانی شده مطابقت داشته باشد. همچنین، نوع آرگومانها در تابع فراخوانی شده باید با نوع پارامترهای متناظر در سرآیند تابع مطابقت داشته باشد. (همانطوری که جلوتر می رویم، شاهد خواهید بود که نوع یک آرگومان می تواند همانند نوع پارامتر متناظر خود نباشد.) در مثال ما، یک آرگومان رشتهای در تابع فراخوانی شده وجود دارد (nameOfCourse) که دقیقاً با پارامتری رشتهای در تعریف تابع عضو مطابقت دارد (CourseName).
به روز کردن دیاگرام کلاس UML برای کلاس GradeBook
دیاگرام کلاس UML در شکل ۴-۳ مبادرت به مدلسازی کلاس GradeBook از برنامه ۳-۳ کرده است. همانند کلاس GradeBook تعریف شده در برنامه ۱-۳، این کلاس GradeBook حاوی یک تابع عضو سراسری displayMessage است. با این وجود، این نسخه از displayMessage دارای یک پارامتر می باشد. UML پارامتر را با لیست کردن نام پارامتر، بدنبال آن یک کولن و سپس نوع پارامتر در درون پرانتزهای قرار گرفته پس از نام عملیات مدلسازی می کند. UML دارای نوع دادههای متعلق بخود شبیه C++ است. UML یک زبان مستقل بوده و از آن در کنار انواع زبانهای برنامهنویسی استفاده می شود، از اینرو اصطلاحات تخصصی آن دقیقاً مطابق با C++ نیست. برای مثال، نوع رشته (String) در UML متناظر با نوع string در C++ است. تابع عضو displayMessage از کلاس GradeBook (شکل ۳-۳ خطوط ۱۸-۲۲) دارای یک پارامتر رشتهای بنام CourseName است، از اینرو در شکل ۴-۳ بصورت courseName : String در میان پرانتزها و پس از نام diaplayName، قرار گرفته است. دقت کنید که این نسخه از کلاس GradeBook هنوز دارای اعضای داده نیست.
شکل ۴-۳ | دیاگرام کلاس UML نشان می دهد که کلاس GradeBook دارای عملیات displayMessage با یک پارامتر از نوع String در UML است.
۶-۳ اعضای داده، توابع set و get
در فصل دوم، تمام متغیرهای برنامه را در تابعmain اعلان کردیم. متغیرهای اعلان شده در بدنه تعریف یک تابع، بنام متغیرهای محلی شناخته می شوند و می توانند فقط از خطی که در آن تابع اعلان شدهاند تا رسیدن به براکت بستن سمت راست (}) در تعریف تابع بکار گرفته شوند. قبل از اینکه بتوان از یک متغیر محلی استفاده کرد، باید ابتدا آن را اعلان کرده باشید. زمانیکه تابع به کار خود خاتمه می دهد، مقادیر متغیرهای محلی آن از بین می روند (در فصل ششم با متغیرهای محلی static آشنا خواهید شد که از این قاعده مستثنی هستند). از بخش ۲-۳ بخاطر دارید که شیی که دارای صفت است، آن را با خود همراه دارد و در برنامه از آن استفاده میشود. چنین صفاتی در کل طول عمر یک شی وجود خواهند داشت.
معمولاً کلاسی که دارای یک یا چندین تابع عضو است، مبادرت به دستکاری کردن صفات متعلق به یک شی مشخص از کلاسی میکند. صفات به عنوان متغیرهای در تعریف کلاس عرضه میشوند. چنین متغیرهای، بنام اعضای داده شناخته میشوند و در درون تعریف کلاس اعلان میگردند اما در خارج از تعریف بدنه تابع عضو کلاس جای میگیرند. هر شی از کلاس مسئول نگهداری کپی از صفات متعلق به خود در حافظه است. مثال مطرح شده در این بخش به توصیف کلاس GradeBook میپردازد که حاوی یک عضو داده CourseName است تا نشاندهنده نام یک دوره خاص از شی GradeBook باشد.
کلاس GradeBook با یک عضو داده، یک تابع set و get
در این مثال، کلاس GradeBook (برنامه شکل ۵-۳) مبادرت به نگهداری نام دوره بصورت یک عضو داده میکند و از اینروست که میتواند بکار گرفته شده یا در هر زمان اجرای برنامه آن را اصلاح کرد. کلاس حاوی توابع عضو setCourseName، getCourseName و displayMessage است. تابع عضو setCourseName نام دوره را در عضو داده GradeBook ذخیره می سازد. تابع عضو getCourseName نام دوره را از عضو داده بدست می آورد. تابع عضو displayMessage که هیچ پارامتری ندارد، پیغام خوشآمدگویی را که شامل نام دوره است، به نمایش در می آورد. با این همه، همانطوری که مشاهده میکنید، در حال حاضر تابع، نام دوره را با فراخوانی تابع دیگری در همان کلاس بدست می آورد، تابع getCourseName.
شکل ۵-۳ | تعریف و تست کلاس GradeBook با یک عضو داده و توابع set و get.
معمولاً یک مدرس بیش از یک دوره را تدریس می کند که هر دوره دارای نام متعلق بخود است. در خط ۳۹، متغیر CourseName از نوع رشته اعلان شده است. بدلیل اینکه متغیر اعلان شده در درون تعریف کلاس اعلان شده (خطوط ۱۵-۴۰) اما در خارج از بدنه تعاریف توابع عضو جای دارد (خطوط ۱۹-۲۲، ۲۵-۲۸ و ۳۱-۳۷)، خط ۳۹ اعلانی برای یک عضو داده است. هر نمونهای (شی) از کلاس GradeBookGradeBook وجود داشته باشد، هر شی دارای یک کپی از CourseName متعلق بخود خواهد بود، همانطوری که در مثال برنامه شکل ۷-۳ شاهد آن خواهید بود. مزیت ایجاد CourseName بصورت یک عضو داده در این است که تمام توابع عضو یک کلاس (در این مورد،GradBook ) می توانند در هر عضو داده موجود که در تعریف کلاس وجود دارد، دستکاری کنند (در این مورد، CourseName). حاوی یک کپی از هر عضو داده کلاس خواهد بود. برای مثال، اگر دو شی
تصریحکننده دسترسی public و private
اکثر اعلانهای اعضای داده پس از برچسب تصریحکننده دسترسی private: ظاهر می شوند (خط ۳۸). همانند public، کلمه کلیدی private یک تصریحکننده است. متغیرها یا توابع اعلان شده پس از private (و قبل از تصریحکننده دسترسی بعدی) فقط در توابع عضو کلاسی که در آن اعلان شدهاند، در دسترس خواهند بود. بنابر این، عضو داده CourseName فقط می تواند در توابع عضو setCourseName، getCourseName و displayMessage از کلاس GradeBook بکار گرفته شود. بدلیل اینکه عضو داده CourseName بصورت private اعلان شده است، نمی تواند توسط توابع خارج از کلاس (همانند main) یا توابع عضو کلاسهای دیگر در برنامه بکار گرفته شود. مبادرت به دسترسی عضو داده courseName در یکی از نقاط این برنامه با عبارتی همانند myGradeBook.courseName خطای کامپایل تولید کرده و پیغامی مشابه
cannot access private member declared in class ‘GradeBook’
به نمایش در می آید.
توابع عضو setCourseName و getCourseName
تابع عضو setCourseName تعریف شده در خطوط ۱۹-۲۲ به هنگام اتمام وظیفه خود هیچ مقداری برگشت نمی دهد و از اینرو نوع برگشتی آن void است. تابع عضو یک پارامتر دریافت میکند، name، که نشاندهنده نام دورهای است که به آن بعنوان یک آرگومان ارسال خواهد شد (خط ۵۵ از main).
خط ۲۱ مبادرت به تخصیص name به عضو داده courseName میکند. در این مثال، setCourseName مبادرت به اعتبارسنجی نام دوره نمی کند (بررسی فرمت نام دوره با یک الگوی خاص). برای نمونه فرض کنید که دانشگاهی میتواند از اسامی دوره تا ۲۵ کاراکتر یا کمتر چاپ بگیرد. در این مورد، مایل هستیم کلاس GradeBook ما را مطمئن سازد که عضو داده courseName هرگز بیش از ۲۵ کاراکتر نداشته باشد. در بخش ۱۰-۳ با تکنیکهای اولیه اعتبارسنجی آشنا خواهید شد.
تابع عضو getCourseName تعریف شده در خطوط ۲۵-۲۸ یک شی خاص از GradeBook بنام courseName را برگشت می دهد. تابع عضو دارای یک لیست پارامتری خالی است و از اینرو برای انجام وظیفه خود نیازی به اطلاعات اضافی ندارد. تابع مشخص می سازد که یک رشته برگشت خواهد داد. زمانیکه تابعی که نوع برگشتی آن بجز void است فراخوانی می شود و وظیفه خود را انجام می دهد، تابع نتیجهای را به فراخوان خود برگشت می دهد. برای مثال، هنگامی که به سراغ یک ATM می روید و تقاضای نمایش میزان موجودی خود را میکنید، انتظار دارید ATM مقداری که نشاندهنده میزان موجودی است به شما برگشت دهد. به همین ترتیب، هنگامی که عبارتی تابع عضو getCourseName از یک شی GradeBook را فراخوانی می کند، عبارت انتظار دریافت نام دوره را دارد (در این مورد، یک رشته است که توسط نوع برگشتی تابع مشخص گردیده است). اگر تابعی بنام square داشته باشید که مربع آرگومان خود را برگشت می دهد، عبارت
int results = square(2);
مقدار ۴ را از تابع square برگشت داده و متغیر result را با ۴ مقداردهی اولیه می کند. اگر تابعی بنام maximum داشته باشید که بزرگترین عدد را از بین سه آرگومان خود برگشت می دهد، عبارت
int biggest = maximum(27,114,41);
عدد ۱۱۴ را از تابع maximum برگشت داده و متغیر biggest با عدد ۱۱۴ مقداردهی اولیه می شود.
توجه کنید که عبارات قرار گرفته در خطوط ۲۱ و ۲۷ هر یک از متغیر courseName (خط ۳۹) استفاده کردهاند، بدون اینکه این متغیر در توابع عضو اعلان شده باشد می توانیم از courseName در توابع عضو کلاس GradeBookاستفاده کنیم چرا که courseName یک عضو داده از کلاس است. همچنین توجه نمائید که ترتیب تعریف توابع عضو تعیینکننده ترتیب فراخوانی در زمان اجرا نیستند از اینرو تابع عضو getCourseName می تواند قبل از تابع عضو setCourseName تعریف شود.
تابع عضو displayMessage
تابع عضو displayMessage در خطوط ۳۱-۳۷ هیچ نوع دادهای را پس از کامل کردن وظیفه خود برگشت نمی دهد، از اینروست که نوع برگشتی آن void تعریف شده است. تابع، پارامتری دریافت نمیکند، بنابر این لیست پارامتری آن خالی است. خطوط ۳۵-۳۶ پیغام خوشآمدگویی را که حاوی مقدار عضو داده courseName است در خروجی چاپ می کنند. خط ۳۵ مبادرت به فراخوانی تابع getCourseNamecourseName می کند. توجه نمائید که تابع عضو displayMessage هم قادر به دسترسی مستقیم به عضو داده courseName است. در مورد اینکه چرا از فراخوانی تابع عضو getCourseName برای بدست آوردن مقدار courseName استفاد کردهایم
سلام آقا این موضوعی که شما گذاشتید دقیقا عین کپی از کتاب Deitel,Deitel ترجمه قلزمه!!!
اشکالی نداره ولی حداقل منبعش رو میزاشتید....