0

آموزش ++C - بخش ششم

 
reza1371
reza1371
کاربر برنزی
تاریخ عضویت : مهر 1388 
تعداد پست ها : 168
محل سکونت : لرستان

آموزش ++C - بخش ششم
یک شنبه 12 اردیبهشت 1389  11:13 PM

کلاس ها و برنامه نویسی شیءگرا
در قسمت های قبلی ، چند برنامه ساده ايجاد كرديم كه مي‌توانستند پيغام‌هاي را به كاربر نشان داده، اطلاعاتي از وي دريافت نمايند، محاسباتي انجام داده و تصميم‌گيري كنند. در اين فصل، شروع به نوشتن برنامه‌هايي مي‌كنيم كه مفاهيم پايه برنامه‌نويسي شي‌گراي معرفي شده در بخش 17-1 را بكار مي‌گيرند. يكي از ويژگي‌هاي مشترك در هر برنامه فصل دوم اين است كه تمام عبارات كه كاري انجام مي‌دهند در تابع
main جاي داده شده‌اند. بطور كلي، برنامه‌هايي كه در اين كتاب ايجاد مي‌كنيد، متشكل از تابع main و يك يا چند كلاس كه هر يك حاوي اعضاي داده و توابع عضو هستند، خواهند بود. اگر شما عضوي از تيم توسعه (طراحي) در يك مجموعه حرفه‌اي هستيد، احتمال دارد بر روي سيستم‌هاي نرم‌افزاري كه حاوي صدها، يا هزاران كلاس است، كار كنيد. در اين فصل، هدف ما توسعه يك چهارچوب كاري ساده خوش‌فرم به لحاظ مهندسي نرم‌افزار به منظور سازماندهي برنامه‌هاي شي‌گرا در C++ است.

ابتدا توجه خود را به سمت كلاس‌هاي موجود در دنياي واقعي متمركز مي‌كنيم. سپس به آرامي به سمت دنباله‌اي از هفت برنامه كامل مي‌رويم كه به توصيف نحوه ايجاد و استفاده از كلاس‌‌هاي متعلق به خودمان مي‌پردازند. اين مثال‌ها با مبحث آموزشي هدفمند كه بر توسعه كلاس grade-book تمركز دارد، شروع مي‌شود و مربي مي‌تواند از آن براي نگهداري امتيازات دانشجو استفاده كند. اين مبحث آموزشي در چند فصل آتي بهبود خواهد يافت و در فصل هفتم بحد اعلي خود خواهد رسيد.

2-3       كلاس‌ها، شي‌ها، توابع عضو و داده

اجازه دهيد بحث را با يك مقايسه ساده كه در افزايش درك شما از مطالب بخش 17-1 موثر است آغاز كنيم. فرض كنيد كه مي‌خواهيد با اتومبيلي رانندگي كرده و با فشردن پدال گاز آن را سريعتر به حركت در آوريد. چه اتفاقي قبل از اينكه بتوانيد اينكار را انجام دهيد، بايد رخ دهد؟ بسيار خوب، قبل از اينكه بتوانيد با اتومبيلي رانندگي كنيد، بايد كسي آن را طراحي و ساخته باشد. معمولاً ساخت اتومبيل، با ترسيم يا نقشه‌كشي مهندسي شروع شود. همانند طراحي صورت گرفته براي خانه. اين ترسيمات شامل طراحي پدال گاز است كه راننده با استفاده از آن سبب مي‌شود تا اتومبيل سريعتر حركت كند. تا حدي، پدال سبب «پنهان» شدن پيچيدگي مكانيزمي مي‌شود كه اتومبيل را سريعتر بحركت در مي‌آورد، همانطوري كه پدال ترمز سبب «پنهان» شدن مكانيزمي مي‌شود كه از سرعت اتومبيل كم مي‌كند، فرمان اتومبيل سبب «پنهان» شدن مكانيزمي مي‌شود كه اتومبيل را هدايت مي‌كند و موارد ديگر. با انجام چنين كارهايي، افراد عادي مي‌توانند به آساني اتومبيل را هدايت كرده و براحتي از پدال گاز، ترمز و فرمان، مكانيزم تعويض دنده و ساير «واسط‌هاي» كاربرپسند و ساده استفاده كنند تا پيچيدگي مكانيزم‌هاي داخلي اتومبيل براي راننده مشخص نباشد.

متاسفانه، نمي‌توانيد با نقشه‌هاي ترسيمي يك اتومبيل رانندگي كنيد، قبل از اينكه با اتومبيلي رانندگي كنيد بايد، آن اتومبيل از روي نقشه‌هاي ترسيمي ساخته شود. يك اتومبيل كاملاً ساخته شده داراي پدال گاز واقعي براي به حركت درآوردن سريع اتومبيل است. اما اين هم كافي نيست، اتومبيل بخودي خود شتاب نمي‌گيرد، از اينرو لازم است راننده بر روي پدال گاز فشار آورد تا به اتومبيل دستور حركت سريع‌تر را صادر كند.

حال اجازه دهيد تا از مثال اتومبيل مطرح شده براي معرفي مفاهيم كليدي برنامه‌نويسي شي‌گرا در اين بخش استفاده كنيم. انجام يك وظيفه در يك برنامه مستلزم يك تابع (همانند main كه فصل دوم توضيح داده شده) است. تابع، توصيف‌كننده مكانيزمي است كه وظيفه واقعي خود را به انجام مي‌رساند. تابع پيچيدگي وظايفي كه قرار است انجام دهد از ديد كاربر خود پنهان مي‌سازد، همانند پدال گاز در اتومبيل كه پيچيدگي مكانيزم شتاب‌گيري را از ديد راننده پنهان مي‌كند. در‍ C++ ، كار را با ايجاد واحدي بنام كلاس كه خانه تابع محسوب مي‌شود، آغاز مي‌كنيم، همانند نقشه ترسيمي اتومبيل كه طرح پدال گاز نيز در آن قرار دارد. از بخش 17-1 بخاطر داريد كه به تابع متعلق به يك كلاس، تابع عضو گفته مي‌شود. در يك كلاس مي‌توان يك يا چند تابع عضو داشت كه براي انجام وظايف كلاس طراحي شده‌اند. براي مثال، يك كلاس مي‌تواند نشان‌دهنده يك حساب بانكي و حاوي يك تابع عضو براي ميزان سپرده در حساب، تابع ديگري براي ميزان برداشت پول از حساب و تابع سومي هم براي نمايش ميزان پول موجود در حساب باشد.

همانطوري كه نمي‌توانيد با نقشه ترسيمي اتومبيل رانندگي كنيد، نمي‌توانيد كلاسي را مشتق كنيد. همانطوري كه بايد قبل از اينكه بتوانيد با اتومبيلي رانندگي كنيد، شخص از روي نقشه ترسيمي مبادرت به ساخت اتومبيل كرده باشد، شما هم بايد قبل از اينكه برنامه بتواند وظايف توصيفي در كلاس را بدست آورد، بايد يك شي از كلاس را ايجاد كرده باشيد. اين يكي از دلايل شناخته شدن C++ بعنوان يك زبان برنامه‌نويسي شي‌گرا است. همچنين توجه نمائيد كه همانطوري كه مي‌توان از روي نقشه ترسيمي اتومبيل‌هاي متعددي ساخت، مي‌توان از روي يك كلاس، شيي‌هاي متعددي ايجاد كرد.

زمانيكه رانندگي مي‌كنيد، با فشردن پدال گاز، پيغامي به اتومبيل ارسال مي‌شود كه وظيفه‌اي را انجام دهد، كه اين وظيفه افزودن سرعت اتومبيل است. به همين ترتيب، پيغام‌هايي را به يك شي ارسال مي‌كنيم، هر پيغام بعنوان فراخوان يك تابع عضو شناخته مي‌شود و به تابع عضو از شيي اعلان مي‌كند كه وظيفه خود را انجام دهد. اينكار غالباً بعنوان تقاضاي سرويس از يك شي شناخته مي‌شود.

تا بدين‌جا، از مقايسه اتومبيل براي توضيح كلاس‌ها، شي‌ها و توابع عضو استفاده كرديم. علاوه بر قابليت‌هاي اتومبيل، هر اتومبيلي داراي چندين صفت است، صفاتي همانند رنگ، تعداد درها، ظرفيت باك، سرعت جاري و مسافت طي شده. همانند قابليت‌هاي اتومبيل، اين صفات هم بعنوان بخشي از طراحي اتومبيل در نقشه ترسيمي ديده مي‌شوند. همانطوري كه رانندگي مي‌كنيد، اين صفات هميشه در ارتباط با اتومبيل هستند. هر اتومبيلي، حافظ صفات خود است. براي مثال، هر اتومبيلي از ميزان سوخت موجود در باك خود مطلع است، اما از ميزان سوخت موجود در باك ساير اتومبيل‌ها مطلع نيست. به همين ترتيب، يك شي داراي صفاتي است كه به همراه شي بوده و در برنامه بكار گرفته مي‌شوند.

اين صفات به عنوان بخشي از كلاس‌ شي تصريح مي‌شوند. براي مثال، يك شي حساب بانكي داراي صفت موجودي است كه نشاندهنده مقدار پول موجود در حساب مي‌باشد. هر شي حساب بانكي از ميزان موجودي در حساب خود مطلع است، اما از موجودي ساير حساب‌ها در بانك اطلاعي ندارد. صفات توسط اعضاي داده كلاس مشخص مي‌شوند.

3-3       نگاهي بر مثال‌هاي اين فصل

در مابقي اين فصل مبادرت به معرفي هفت مثال ساده مي‌كنيم كه به توصيف مفاهيم معرفي شده در ارتباط با قياس اتومبيل مي‌پردازند. خلاصه‌اي از اين مثال‌ها در زير آورده شده است. ابتدا مبادرت به ايجاد كلاس GradeBook مي‌كنيم تا قادر به توصيف اين مفاهيم باشيم:

1- اولين مثال نشاندهنده كلاس GradeBook با يك تابع عضو است كه فقط يك پيغام خوش‌آمدگويي را در زمان فراخواني به نمايش در مي‌آورد. سپس شما را با نحوه ايجاد يك شي از اين كلاس و فراخواني تابع عضو كه پيغام خوش‌آمدگويي را ظاهر مي‌سازد، آشنا خواهيم كرد.

2- دومين مثال، اصلاح شده مثال اول است. در اين مثال به تابع عضو اجازه داده مي‌شود تا نام دوره را به عنوان يك آرگومان قبول كند. سپس، تابع عضو مبادرت به نمايش نام دوره بعنوان بخشي از پيغام‌ خوش‌آمدگويي مي‌كند.

3- سومين مثال نحوه ذخيره‌سازي نام دوره در يك شي GradeBook را نشان مي‌دهد. براي اين نسخه از كلاس، شما را با نحوه استفاده از توابع عضو به منظور تنظيم نام دوره در شي و بدست آوردن نام دوره از شي آشنا مي‌كنيم.

4- چهارمين مثال به توصيف نحوه مقداردهي اوليه داده در شي GradeBook به هنگام ايجاد شي مي‌پردازد. مقداردهي اوليه توسط يك تابع عضو بنام سازنده كلاس صورت مي‌گيرد. همچنين اين مثال نشان مي‌دهد كه هر شي GradeBook از نام دورة خود نگهداري مي‌كند.

5- مثال پنجم اصلاح شده مثال چهارم است كه به توصيف نحوه قرار دادن كلاس GradeBook در يك فايل مجزا به منظوراستفاده مجدد از نرم‌افزار، مي‌پردازد.

6- مثال ششم، تغييريافته مثال پنجم است كه حاوي يك اصل مهندسي نرم‌افزار در جداسازي بخش واسط كلاس از بخش پياده‌سازي آن است. با انجام اينكار فرآيند اصلاح و تغيير آسانتر مي‌شود بدون اينكه در سرويس‌گيرنده‌هاي كلاس تاثيرگذار باشد.

7- آخرين مثال قابليت كلاس GradeBook را با معرفي اعتبارسنجي داده افزايش خواهد داد. اعتبارسنجي ما را از فرمت صحيح داده در يك شي مطمئن مي‌سازد. براي مثال يك شي Date نيازمند يك مقدار در محدودة 1 الي 12 است. در اين مثال GradeBook ، تابع عضوي كه مبادرت به تنظيم نام دورة براي يك شي GradeBook مي‌كند، سبب مي‌شود تا نام دوره 25 كاراكتر يا كمتر باشد. اگر طول نام دوره بيش از 25 كاراكتر باشد، تابع عضو فقط از 25 كاراكتر اول استفاده كرده و يك پيغام خطا به نمايش در مي‌آورد.

توجه كنيد كه مثال‌هاي GradeBook در اين فصل فرآيند واقعي ذخيره‌سازي را انجام نمي‌دهند. در فصل چهارم، فرآيند پردازش امتيازات را با GradeBook و در فصل هفتم مبادرت به ذخيره‌سازي اطلاعات در يك شي GradeBook خواهيم كرد.

4-3       تعريف كلاس با يك تابع عضو

كار را با مثالي آغاز مي‌كنيم (شكل 1-3) كه حاوي كلاس GradeBook است و مي‌توان از آن براي نگهداري امتيازات دانشجويان استفاده كرد. تابع main در خطوط 20-25 مبادرت به ايجاد يك شي GradeBook كرده است. اين برنامه نسخه اول بوده و نسخه كامل آن در فصل هفتم ايجاد خواهد شد. تابع main از اين شي و تابع عضو آن براي نمايش پيغام بر روي صفحه نمايش (پيغام ‌خوش‌آمدگويي) استفاده مي‌كند.

1    // Fig. 3.1: fig03_01.cpp

2    // Define class GradeBook with a member function displayMessage;

3    // Create a GradeBook object and call its displayMessage function.

4    #include <iostream>

5    using std::cout;

6    using std::endl;

7     

8    // GradeBook class definition

9    class GradeBook

10  {

11  public:

12     // function that displays a welcome message to the GradeBook user

13     void displayMessage()

14     {

15        cout << "Welcome to the Grade Book!" << endl;

16     } // end function displayMessage

17  }; // end class GradeBook 

18   

19  // function main begins program execution

20  int main()

21  {

22     GradeBook myGradeBook; // create a GradeBook object named myGradeBook

23     myGradeBook.displayMessage(); // call object's displayMessage function

24     return 0; // indicate successful termination

25  } // end main

Welcome to the Grade Book!

شكل 1-3 | تعريف كلاس GradeBook با يك تابع عضو، ايجاد يك شي GradeBook و فراخواني تابع عضو آن.

ابتدا به توصيف نحوه تعريف يك كلاس و تابع عضو مي‌پردازيم. سپس به توضيح نحوه ايجاد يك شي و نحوه فراخواني تابع عضو يك شي مي‌پردازيم. چند مثال اول حاوي تابع main و كلاس GradeBook است كه از آن در همان فايل استفاده مي‌كند. در انتهاي اين فصل، به معرفي روش‌هاي خبره در ساختارمند كردن برنامه‌ها به منظور افزايش كارايي و انجام بهتر مهندسي‌ نرم‌افزار خواهيم پرداخت.

كلاس GradeBook

قبل ا ز اينكه تابع main (خطوط 20-25 ) بتواند شي از كلاس GradeBook ايجاد كند، بايستي به كامپايلر توابع عضو و اعضاي داده متعلق به كلاس را اعلان كنيم. اين كار بنام تعريف كلاس شناخته مي‌شود. تعريف كلاس GradeBook (خطوط 9-17 ) حاوي تابع عضوي بنام displayMessage است (خطوط 13-16 ) كه پيغامي بر روي صفحه نمايش چاپ مي‌كند (خط 15 ). بخاطر داريد كه يك كلاس همانند يك نقشه ترسيمي است، از اينرو نياز داريم كه يك شي از كلاس GradeBook ايجاد كنيم (خط 22 )، و تابع عضو displayMessage آن را فراخواني نمايم (خط 23 ) تا خط 15 را به اجرا درآورده و پيغام خوش‌آمدگويي را به نمايش درآورد. بزودي به توضيح دقيق‌تر خطوط 22-23 خواهيم پرداخت.

تعريف كلاس از خط 9 و با كلمه كليدي class و بدنبال آن نام كلاس GradeBook آغاز شده است. بطور قراردادي، نام كلاس‌هاي تعريف شده توسط كاربر با حروف بزرگ شروع مي‌شوند و در صورت وجود كلمات بعدي، ابتداي آنها هم با حروف بزرگ آغاز مي‌گردد. به اين روش غالباً روش camel case مي‌گويند.

بدنه هر كلاسي در بين جفت براكت باز و بسته ( } و { ) محدود مي‌شود، همانند خطوط 10 و 17 . تعريف كلاس با يك سيمكولن خاتمه مي‌پذيرد (خط 17 ).

خطاي برنامه‌نويسي

فراموش كردن سيمكولن در انتهاي تعريف يك كلاس، خطاي نحوي بدنبال خواهد داشت.

بخاطر داريد كه تابع main هميشه و بصورت اتوماتيك به هنگام اجراي برنامه فراخواني مي‌شود. اكثر توابع بصورت اتوماتيك فراخواني نمي‌شوند. همانطوري كه مشاهده خواهيد كرد، بايستي تابع عضو displayMessage را بطور صريح فراخواني كنيد تا وظيفه خود را انجام دهد.

خط 14 حاوي برچسب تصريح‌كننده دسترسي public: است. كلمه كليدي public ، تصريح‌كننده دسترسي ناميده مي‌شود. خطوط 13-16 تعريف‌كننده تابع عضو displayMessage هستند. اين تابع عضو پس از public: قرار دارد تا نشان دهد كه تابع «بصورت سراسري در دسترس است»، به اين معني كه مي‌تواند توسط ساير توابع موجود در برنامه و توسط توابع عضو كلاس‌هاي ديگر فراخواني گردد. هميشه در مقابل تصريح‌كننده‌هاي دسترسي يك كولن ( : ) قرار داده مي‌شود. براي مابقي متن، زمانيكه به تصريح‌كننده دسترسي public اشاره مي‌كنيم، كولن آن را در نظر نمي‌گيريم. در بخش 6-3 به معرفي دومين تصريح‌كننده دسترسي بنام private خواهيم پرداخت.

هر تابعي در برنامه وظيفه‌اي را انجام داده و امكان دارد مقداري را پس از كامل كردن وظيفه خود برگشت دهد. براي مثال، تابعي مي‌تواند يك محاسبه انجام داده و سپس نتيجه آن محاسبه را برگشت دهد. زمانيكه تابعي تعريف مي‌شود، بايد نوع برگشتي آن را مشخص سازيد، تا تابع پس از اتمام كار، آن نوع را برگشت دهد. در خط 13 ، كلمه كليدي void قرار گرفته است (در سمت چپ نام تابع displayMessage ) و نشاندهندة نوع برگشتي از سوي تابع است. نوع برگشتي void بر اين نكته دلالت دارد كه displayMessage وظيفه‌اي را انجام خواهد داد، اما داده‌اي را به فراخوان خود (در اين مثال، تابع فراخوان، main مي‌باشد) پس از اتمام وظيفه خود برگشت نخواهد داد. (در شكل 5-3 مثالي را مشاهده مي‌كنيد كه تابع در آن مقداري را برگشت داده است).

نام تابع عضو displayMessage بوده و قبل از آن نوع برگشتي قرار دارد. بطور قراردادي، اسامي توابع با يك حرف كوچك شروع شده و تمام كلمات متعاقب آن با حرف بزرگ شروع مي‌شوند. پرانتزهاي قرار گرفته پس از نام تابع عضو، بر اين نكته دلالت دارند كه اين يك تابع است. يك جفت پرانتز خالي، همانند خط 13 ، نشان مي‌دهد كه اين تابع عضو، نيازي به داده اضافي براي انجام وظيفه خود ندارد. در بخش 5-3 شاهد تابع عضوي خواهيد بود كه براي انجام وظيفه خود نيازمند داده اضافي است. معمولاً به خط 13 ، سرآيند تابع گفته مي‌شود. بدنه هر تابعي با براكت‌هاي باز و بسته مشخص مي‌شود ( } و { )، همانند خطوط 14 و 16 .

بدنه تابع حاوي عباراتي است كه وظيفه تابع را به انجام مي‌رسانند. در اين مورد، تابع عضو displayMessage حاوي يك عبارت است (خط 15 ) كه پيغام "Welcome to the Grade Book!" را به نمايش در مي‌آورد. پس از اجراي اين عبارت، تابع وظيفه خود را به انجام رسانده است.

خطاي برنامه‌نويسي

برگشت دادن مقداري از يك تابع كه نوع برگشتي آن بصورت void اعلان شده است، خطاي كامپايلر بدنبال خواهد داشت.

خطاي برنامه‌نويسي

تعريف تابعي در درون تابع ديگر، خطاي نحوي است.

تست كلاس GradeBook

در اين مرحله مي‌خواهيم كه از كلاس GradeBook در برنامه استفاده كنيم. همانطوري كه در فصل دوم آموختيد، تابع main با اجراي هر برنامه‌اي شروع بكار مي‌كند. خطوط 20-25 از برنامه شكل 1-3 حاوي تابع main هستند، كه اجراي برنامه را تحت كنترل دارد.

در اين برنامه، مايل هستيم تابع عضو displayMessage از كلاس GradeBook براي نمايش پيغام خوش‌آمدگويي اجرا گردد (فراخواني شود). اصولاً تا زمانيكه شيي از يك كلاس ايجاد نكرده باشيد، نمي‌توانيد تابع عضو كلاس را فراخواني نمائيد (در بخش 7-10 با تابع عضو static ، آشنا خواهيد شد كه در اين مورد يك استثناء مي‌باشد.) خط 22 يك شي از كلاس GradeBook بنام myGradeBook ايجاد مي‌كند. دقت كنيد كه نوع متغير GradeBook است، كلاس تعريف شده در خطوط 9-17 . زمانيكه متغيرهايي از نوع int اعلان مي‌كنيم، همانند كاري كه در فصل دوم انجام داديم، كامپايلر از مفهوم int مطلع است و مي‌داند كه آن يك نوع بنيادين مي‌باشد. با اين وجود، زمانيكه مبادرت به نوشتن خط 22 مي‌كنيم، كامپايلر بصورت اتوماتيك از مفهوم نوع GradeBook اطلاعي ندارد و آن را نمي‌شناسد، اين نوع يك نوع تعريف شده توسط كاربر است. از اينرو، بايد به كامپايلر، با قرار دادن تعريف كلاس همانند كاري كه در خطوط 9-17 انجام داده‌ايم، GradeBook را معرفي كنيم. اگر اين خطوط را حذف كنيم، كامپايلر پيغام خطايي همانند " 'GradeBook' : undeclared identifier" را در GNU C++ صادر مي‌كند. هر كلاس جديدي كه ايجاد مي‌كنيد، تبديل به يك نوع جديد مي‌شود كه مي‌تواند براي ايجاد شي‌ها بكار گرفته شود. برنامه‌نويسان مي‌توانند در صورت نياز مبادرت به تعريف كلاس‌هاي با نوع جديد نمايند، و اين يكي از دلايل شناخته شدن ‍ C++ بعنوان يك زبان بسط‌پذير است.

خط 23 مبادرت به فراخواني تابع عضو displayMessage (تعريف شده در خطوط 13-16 ) با استفاده از متغير myGradeBook و بدنبال آن عملگر نقطه ( . )، سپس نام تابع displayMessage و يك جفت پرانتز خالي مي‌كند. اين فراخواني موجب مي‌شود كه تابع displayMessage براي انجام وظيفه خود فراخواني شود. در ابتداي خط 23 ، عبارت "myGradeBook." بر اين نكته دلالت دارد كه main بايستي از شي GradeBook كه در خط 22 ايجاد شده است، استفاده نمايد. پرانتزهاي خالي در خط 13 نشان مي‌دهند كه تابع عضو displayMessage نيازي به داده اضافي براي انجام وظيفه خود ندارد. (در بخش 5-3، با نحوه ارسال داده به تابع آشنا خواهيد شد) زمانيكه displayMessage وظيفه خود را انجام داد، تابع main به اجراي خود از خط 24 ادامه خواهد داد، كه نشان مي‌دهد main وظيفه خود را به بدرستي انجام داده است. با رسيدن به انتهاي main ، برنامه خاتمه مي‌پذيرد.

دياگرام كلاس UML براي كلاس GradeBook

از بخش 17-1 بخاطر داريد كه UML يك زبان گرافيكي بكار رفته توسط برنامه‌نويس براي نمايش سيستم‌هاي شي‌گرا به يك روش استاندارد است. در UML ، هر كلاس در يك دياگرام كلاس و بصورت يك مستطيل با سه قسمت (بخش) مدل‌سازي مي‌شود. شكل 2-3 نشاندهنده يك دياگرام كلاس UML براي كلاس GradeBook معرفي شده در برنامه 1-3 است. بخش فوقاني حاوي نام كلاس است، كه در وسط قرار گرفته و بصورت توپر نوشته مي‌شود. بخش مياني، حاوي صفات كلاس است كه مرتبط با اعضاي داده در C++ است. در شكل 2-3 بخش مياني خالي است، چرا كه اين نسخه از كلاس GradeBook در برنامه 1-3 داراي صفات نيست. (در بخش 6-3 نسخه‌اي از كلاس GradeBook عرضه شده كه داراي يك صفت است.) بخش تحتاني حاوي عمليات كلاس است، كه متناظر با توابع عضو در C++ مي‌باشد.

 

شكل 2-3 | دياگرام كلاس UML نشان مي‌دهد كه كلاس GradeBook داراي يك عمليات سراسري بنام displayMessage است.

UML مبادرت به مدلسازي عمليات‌ها با ليست كردن نام عمليات و بدنبال آن مجموعه پرانتزها مي‌كند. كلاس GradeBook فقط داراي يك تابع عضو بنام displayMessage است، از اينرو بخش تحتاني در شكل 2-3 فقط يك عمليات با اين نام را ليست كرده است. تابع عضو displayMessage براي انجام وظيفه خود نيازي به اطلاعات اضافي ندارد، از اينرو پرانتزهاي قرار گرفته پس از displayMessage در اين دياگرام كلاس خالي هستند، همانند سرآيند تابع عضو قرار گرفته در خط 13 برنامه1-3. علامت جمع ( + ) كه قبل ا ز نام عمليات آورده شده، نشان مي‌دهد كه displayMessage يك عمليات سراسري در UML است (يك تابع عضو public در ‍ C++ ). به دفعات از دياگرام‌هاي كلاس UML براي خلاصه كردن صفات و عمليات كلاس‌ها استفاده خواهيم كرد.

5-3       تعريف تابع عضو با پارامتر

در مثال قياس اتومبيل در بخش 2-3 خاطرنشان كرديم كه فشردن پدال گاز سبب ارسال پيغامي به اتومبيل مي‌شود تا وظيفه‌اي را به انجام برساند، كه در اين مورد افزودن سرعت اتومبيل است. اما اتومبيل بايد چقدر سرعت بگيرد؟ همانطوري كه مي‌دانيد، با فشردن هر چه بيشتر پدال، سرعت اتومبيل افزايش پيدا مي‌كند. بنابر اين پيغام ارسالي به اتومبيل هم حاوي وظيفه بوده و همچنين حاوي اطلاعات ديگري است كه به اتومبيل در انجام وظيفه كمك مي‌كند. اين اطلاعات اضافي بنام پارامتر شناخته مي‌شوند، مقدار پارامتر به اتومبيل كمك مي‌كند تا ميزان افزايش سرعت را تعيين كند. به همين ترتيب، يك تابع عضو مي‌تواند نيازمند يك يا چندين پارامتر بعنوان داده اضافي براي انجام وظيفه خود باشد. فراخوان تابع مقاديري بنام آرگومان، براي هر پارامتر تابع تدارك مي‌بيند. براي مثال، در سپرده‌گذاري در حساب بانكي، فرض كنيد تابع عضو deposit از كلاس Account پارامتري كه نشاندهنده مقدار سپرده است، مشخص كرده باشد. زمانيكه تابع عضو deposit فراخواني شود، مقدار آرگومان كه نشاندهنده مقدار سپرده است به پارامتر تابع عضو كپي مي‌شود. سپس تابع عضو اين مقدار سپرده را به ميزان موجودي اضافه مي‌كند.

تعريف و تست كلاس GradeBook

مثال بع دي (برنامه شكل 3-3) تعريف مجددي از كلاس GradeBook (خطوط 14-23 ) با تابع عضو displayMessage است (خطوط 18-22 ) كه نام دوره را بعنوان بخشي از رشته خوش‌آمدگويي چاپ مي‌كند. تابع عضو جديد displayMessage مستلزم يك پارامتر است ( courseName در خط 18 ) كه نشاندهنده نام دوره است.

قبل از اينكه به بررسي ويژگي‌هاي جديد كلاس GradeBook بپردازيم، اجازه دهيد به نحوه استفاده از كلاس جديد در main نگاهي داشته باشيم طوط 26-40 ). در خط 28 يك متغير از نوع رشته (string) بنام nameOfCourse ايجاد شده است كه از آن براي ذخيره كردن نام دوره وارد شده توسط كاربر استفاده خواهيم كرد. متغير از نوع string نشاندهنده رشته‌اي از كاراكترها همانند "CS101 Introduction to C++ Programming" است. نوع string در واقع شي از كلاس string كتابخانه استاندارد C++ است. اين كلاس در فايل سرآيند <string> تعريف شده و نام string همانند cout ، متعلق به فضاي‌نامي std است. براي اينكه خط 28 قادر به كامپايل شدن باشد، خط 9 حاوي سرآيند <string> است. دقت كنيد كه اعلان using در خط 10 به ما اجازه مي‌دهد تا به آساني در خط 28 از string بجاي std::string استفاده كنيم. براي اين لحظه، مي‌توانيد در مورد متغيرهاي string همانند متغيرهاي از نوع ديگر همانند int فكر كنيد. در بخش 10-3 با قابليت‌هاي string بيشتر آشنا خواهيد شد.

خط 29 يك شي از كلاس GradeBook بنام myGradeBook ايجاد مي‌كند. خط 32 به كاربر اعلان مي‌كند كه نام دوره را وارد سازد. خط 33 مبادرت به خواندن نام دوره از ورودي كاربر كرده و‌ آن را با استفاده از تابع كتابخانه‌اي getline به متغير nameOfCourse تخصيص مي‌دهد. قبل از اينكه به توضيح اين خط از كد بپردازيم، اجازه دهيد تا توضيح دهيم چرا نمي‌توانيم براي بدست آوردن نام دوره فقط بنويسيم

cin>>nameOfCourse;

در اجراي نمونه اين برنامه، ما از نام دوره "CS101 Introduction to C++ Programming" استفاده كرده‌ايم كه حاوي چندين كلمه است. زمانيكه cin با عملگر استخراج به كار گرفته مي‌شود، مبادرت به خواندن كاراكترها تا رسيدن به اولين كاراكتر white-space مي‌كند. از اينرو فقط "CS101" توسط اين عبارت خوانده مي‌شود و براي خواندن مابقي نام دوره مجبور به عمليات ورودي اضافي خواهيم بود.

در اين مثال، مايل هستيم تا كاربر نام كامل دوره را تايپ كرده و كليد Enter را براي تحويل آن به برنامه فشار دهد، و كل نام دوره در متغير رشته‌اي nameOfCourse ذخيره گردد فراخواني تابع getline( cin, nameOfCourse) در خط 33 ، سبب مي‌شود كه كاراكترها (از جمله كاراكترهاي فاصله كه كلمات را از هم در ورودي جدا مي‌كنند) از شي ورودي استاندارد جريان cin (صفحه كليد) تا رسيدن به كاراكتر خط جديد خوانده شده و در متغير رشته‌اي nameOfCourse جاي داده شده و كاراكتر خط جديد حذف مي‌گردد. توجه نمائيد زمانيكه كليد Enter فشرده مي‌شود (در زمان تايپ ورودي)، يك خط جديد (newline) به جريان ورودي افزوده مي‌شود. همچنين توجه كنيد كه فايل سرآيند <string> بايد قرار داشته باشد تا بتوان از تابع getline استفاده كرد. نام اين تابع متعلق به فضاي نامي std است.

1    // Fig. 3.3: fig03_03.cpp

2    // Define class GradeBook with a member function that takes a parameter;

3    // Create a GradeBook object and call its displayMessage function.

4    #include <iostream>

5    using std::cout;

6    using std::cin;

7    using std::endl;

8     

9    #include <string> // program uses C++ standard string class

10 using std::string;

11 using std::getline;

12  

13 // GradeBook class definition

14 class GradeBook

15 {

16 public:

17    // function that displays a welcome message to the GradeBook user

18    void displayMessage( string courseName )

19    {

20       cout << "Welcome to the grade book for\n" << courseName << "!"

21           << endl;

22    } // end function displayMessage

23 }; // end class GradeBook 

24  

25 // function main begins program execution

26 int main()

27 {

28    string nameOfCourse; // string of characters to store the course name

29    GradeBook myGradeBook; // create a GradeBook object named myGradeBook

30    

31    // prompt for and input course name

32    cout << "Please enter the course name:" << endl;

33    getline( cin, nameOfCourse ); // read a course name with blanks

34    cout << endl; // output a blank line

35  

36    // call myGradeBook's displayMessage function

37    // and pass nameOfCourse as an argument

38    myGradeBook.displayMessage( nameOfCourse );

39    return 0; // indicate successful termination

40 } // end main

Please enter the course name:

CS101 Introduction to C++ Programming

 

Welcome to the grade book for

CS101 Introduction to C++ Programming!

شكل 3-3 | تعريف كلاس GradeBook با تابع عضوي كه پارامتر دريافت مي‌كند.

خط 38 تابع عضو displayMessage شي myGradeBook را فراخواني مي‌كند. متغير nameOfCource موجود در درون پرانتزها آرگوماني است كه به تابع displayMessage ارسال مي‌شود، از اينروست كه تابع مي‌تواند وظيفه خود را به انجام رساند. مقدار متغير nameOfCourse در main تبديل به مقدار پارامتر courseName تابع عضو displayMessage در خط 18 مي‌شود. زمانيكه اين برنامه اجرا ‌شود، توجه نمائيد كه تابع عضو displayMessage به همراه پيغام خوش‌آمدگويي، نام دورة تايپ شده توسط كاربر را به نمايش درمي‌آورد.

آرگومان‌ها و پارامترهاي بيشتر

براي تصريح اينكه تابعي ني ازمند داده براي انجام وظايف خويش است، اطلاعات اضافي را در ليست پارامتري تابع قرار مي‌دهيم، ليستي كه در درون پرانتزها قرار گرفته پس از نام تابع جاي دارد. ليست پارامترها مي‌تواند به هر تعداد پارامتر داشته باشد يا اصلاً پارامتري نداشته باشد (همانند پرانتزهاي خالي در خط 13 برنامه شكل 1-3) تا نشان دهد تابع نياز به هيچ پارامتري ندارد. ليست پارامتري تابع عضو displayMessage به نحوي اعلان شده كه تابع نيازمند يك پارامتر است (شكل 3-3، خط 18 ). هر پارامتر بايد داراي نوع و يك شناسه باشد. در اين مورد، نوع string بوده و شناسه courseName است و نشان مي‌دهد كه تابع عضو displayMessage مستلزم يك رشته براي انجام وظيفه خويش است. بدنه تابع عضو از پارامتر courseName براي دسترسي به مقدار ارسالي به تابع در فراخواني تابع (خط 38 در main ) استفاده مي‌كند. خطوط 20-21 مقدار پارامتر courseName را بعنوان بخشي از پيغام خوش‌آمدگويي به نمايش در مي‌آورد. توجه نمائيد كه نام متغير پارامتري (خط 18 ) مي‌تواند همنام متغير آرگومان (خط 38 ) يا نام متفاوتي داشته باشد. در فصل ششم با دلايل اينكارها آشنا خواهيد شد.

يك تابع مي‌تواند داراي چندين پارامتر باشد، بشرطي كه هر پارامتر از ديگري با يك ويرگول مجزا شده باشد (در مثال شكل‌هاي 4-6 و 5-6 شاهد آنها خواهيد بود). تعداد و ترتيب آرگومان‌ها در يك تابع فراخواني شده بايستي با تعداد و ترتيب ليست پارامترها در سرآيند تابع عضو فراخواني شده مطابقت داشته باشد. همچنين، نوع آرگومان‌ها در تابع فراخواني شده بايد با نوع پارامترهاي متناظر در سرآيند تابع مطابقت داشته باشد. (همانطوري كه جلوتر مي‌رويم، شاهد خواهيد بود كه نوع يك آرگومان مي‌تواند همانند نوع پارامتر متناظر خود نباشد.) در مثال ما، يك آرگومان رشته‌اي در تابع فراخواني شده وجود دارد (nameOfCourse) كه دقيقاً با پارامتري رشته‌اي در تعريف تابع عضو مطابقت دارد (CourseName) .

خطاي برنامه‌نويسي

قراردادن يك سيمكولن پس از پرانتز سمت راست در ليست پارامتري تعريف تابع، خطاي نحوي است.

 

خطاي برنامه‌نويسي

تعريف يك پارامتر تابع همانند يك متغير محلي در تابع، خطاي كامپايل بدنبال خواهد داشت.

برنامه‌نويسي ايده‌ال

از ابهام اجتناب كنيد، از اسامي يكسان براي آرگومان‌هاي ارسالي به تابع و پارامترهاي متناظر در تعريف تابع، استفاده نكنيد.

برنامه‌نويسي ايده‌ال

براي توابع و پارامترها اسامي با معني انتخاب كنيد تا خوانايي برنامه افزايش يافته و نياز به افزودن توضيحات را كم نمايد.

به روز كردن دياگرام كلاس UML براي كلاس GradeBook

دياگرام كلاس UML در شكل 4-3 مبادرت به مدلسازي كلاس GradeBook از برنامه 3-3 كرده است. همانند كلاس GradeBook تعريف شده در برنامه 1-3، اين كلاس GradeBook حاوي يك تابع عضو سراسري displayMessage است. با اين وجود، اين نسخه از displayMessage داراي يك پارامتر مي‌باشد. UML پارامتر را با ليست كردن نام پارامتر، بدنبال آن يك كولن و سپس نوع پارامتر در درون پرانتزهاي قرار گرفته پس از نام عمليات مدل‌سازي مي‌كند. UML داراي نوع داده‌هاي متعلق بخود شبيه C++ است.  UML يك زبان مستقل بوده و از آن در كنار انواع زبان‌هاي برنامه‌نويسي استفاده مي‌شود، از اينرو اصطلاحات تخصصي آن دقيقاً مطابق با C++ نيست. براي مثال، نوع رشته (String) در UML متناظر با نوع string در C++ است. تابع عضو displayMessage از كلاس GradeBook (شكل 3-3 خطوط 18-22 ) داراي يك پارامتر رشته‌اي بنام CourseName است، از اينرو در شكل 4-3 بصورت courseName : String در ميان پرانتزها و پس از نام diaplayName ، قرار گرفته است. دقت كنيد كه اين نسخه از كلاس GradeBook هنوز داراي اعضاي داده نيست.

 

شكل 4-3 | دياگرام كلاس UML نشان مي‌دهد كه كلاس GradeBook داراي عمليات displayMessage با يك پارامتر از نوع String در UML است.

6-3       اعضاي داده، توابع set و get

در فصل دوم، تمام متغيرهاي برنامه را در تابع main  اعلان كرديم. متغيرهاي اعلان شده در بدنه تعريف يك تابع، بنام متغيرهاي محلي شناخته مي‌شوند و مي‌توانند فقط از خطي كه در آن تابع اعلان شده‌اند تا رسيدن به براكت بستن سمت راست ( } ) در تعريف تابع بكار گرفته شوند. قبل از اينكه بتوان از يك متغير محلي استفاده كرد، بايد ابتدا آن را اعلان كرده باشيد. زمانيكه تابع به كار خود خاتمه مي‌دهد، مقادير متغيرهاي محلي آن از بين مي‌روند (در فصل ششم با متغيرهاي محلي static آشنا خواهيد شد كه از اين قاعده مستثني هستند). از بخش 2-3 بخاطر داريد كه شيي كه داراي صفت است، آن را با خود همراه دارد و در برنامه از آن استفاده مي‌شود. چنين صفاتي در كل طول عمر يك شي وجود خواهند داشت.

معمولاً كلاسي كه داراي يك يا چندين تابع عضو است، مبادرت به دستكاري كردن صفات متعلق به يك شي مشخص از كلاسي مي‌كند. صفات به عنوان متغيرهاي در تعريف كلاس عرضه مي‌شوند. چنين متغيرهاي، بنام اعضاي داده شناخته مي‌شوند و در درون تعريف كلاس اعلان مي‌گردند اما در خارج از تعريف بدنه تابع عضو كلاس جاي مي‌گيرند. هر شي از كلاس مسئول نگهداري كپي از صفات متعلق به خود در حافظه است. مثال مطرح شده در اين بخش به توصيف كلاس GradeBook مي‌پردازد كه حاوي يك عضو داده CourseName است تا نشان‌دهنده نام يك دوره خاص از شي GradeBook باشد.

كلاس GradeBook با يك عضو داده، يك تابع set و get

در اين مثال، كلاس GradeBook (برنامه شكل 5-3) مبادرت به نگهداري نام دوره بصورت يك عضو داده مي‌كند و از اينروست كه مي‌تواند بكار گرفته شده يا در هر زمان اجراي برنامه آن را اصلاح كرد. كلاس حاوي توابع عضو setCourseName ، getCourseName و displayMessage است. تابع عضو setCourseName نام دوره را در عضو داده GradeBook ذخيره مي‌سازد. تابع عضو getCourseName نام دوره را از عضو داده بدست مي‌آورد. تابع عضو displayMessage كه هيچ پارامتري ندارد، پيغام خوش‌آمدگويي را كه شامل نام دوره است، به نمايش در مي‌آورد. با اين همه، همانطوري كه مشاهده مي‌كنيد، در حال حاضر تابع، نام دوره را با فراخواني تابع ديگري در همان كلاس بدست مي‌آورد، تابع getCourseName .

1    // Fig. 3.5: fig03_05.cpp

2    // Define class GradeBook that contains a courseName data member

3    // and member functions to set and get its value;

4    // Create and manipulate a GradeBook object.

5    #include <iostream>

6    using std::cout;

7    using std::cin;

8    using std::endl;

9     

10  #include <string> // program uses C++ standard string class

11  using std::string;

12  using std::getline;

13   

14  // GradeBook class definition

15  class GradeBook

16  {

17  public:

18     // function that sets the course name

19     void setCourseName( string name )

20     {     

21        courseName = name; // store the course name in the object

22     } // end function setCourseName

23     

24     // function that gets the course name

25     string getCourseName()

26     {

27        return courseName; // return the object's courseName

28     } // end function getCourseName

29   

30     // function that displays a welcome message

31     void displayMessage()

32     {

33        // this statement calls getCourseName to get the

34        // name of the course this GradeBook represents

35       cout << "Welcome to the grade book for\n" << getCourseName() << "!"

36           << endl;

37     } // end function displayMessage

38  private:

39     string courseName; // course name for this GradeBook

40  }; // end class GradeBook 

41   

42  // function main begins program execution

43  int main()

44  {

45      string nameOfCourse; // string of characters to store the course name

46     GradeBook myGradeBook; // create a GradeBook object named myGradeBook

47     

48     // display initial value of courseName

49     cout << "Initial course name is: " << myGradeBook.getCourseName()

50        << endl;

51   

52     // prompt for, input and set course name

53     cout << "\nPlease enter the course name:" << endl;

54     getline( cin, nameOfCourse ); // read a course name with blanks

55     myGradeBook.setCourseName( nameOfCourse ); // set the course name

56   

57     cout << endl; // outputs a blank line

58     myGradeBook.displayMessage(); // display message with new course name

59     return 0; // indicate successful termination

60  } // end main

Initial course name is:

 

Please enter the course name:

CS101 Introduction to C++ Programming

 

Welcome to the grade book for

CS101 Introduction to C++ Programming!

شكل 5-3 | تعريف و تست كلاس GradeBook با يك عضو داده و توابع set و get .

 

برنامه‌نويسي ايده‌ال

يك خط خالي مابين تعريف تابع عضو قرار دهيد تا خوانايي برنامه افزايش پيدا كند.

معمولاً يك مدرس بيش از يك دوره را تدريس مي‌كند كه هر دوره داراي نام متعلق بخود است. در خط 39 ، متغير CourseName از نوع رشته اعلان شده است. بدليل اينكه متغير اعلان شده در درون تعريف كلاس اعلان شده (خطوط 15-40 ) اما در خارج از بدنه تعاريف توابع عضو جاي دارد (خطوط 19-22 ، 25-28 و 31-37 )، خط 39 اعلاني براي يك عضو داده است. هر نمونه‌اي (شي) از كلاس GradeBook حاوي يك كپي از هر عضو داده كلاس خواهد بود. براي مثال، اگر دو شي GradeBook وجود داشته باشد، هر شي داراي يك كپي از CourseName متعلق ب خ ود خواهد بود، همانطوري كه در مثال برنامه شكل 7-3 شاهد آن خواهيد بود. مزيت ايجاد CourseName بصورت يك عضو داده در اين است كه تمام توابع عضو يك كلاس (در اين مورد، GradBook ) مي‌توانند در هر عضو داده موجود كه در تعريف كلاس وجود دارد، دستكاري كنند (در اين مورد، CourseName ).

 

تشکرات از این پست
iman_karbala
دسترسی سریع به انجمن ها