در زبانهای برنامه نویسی، از جمله زبان برنامه نویسی C، از تکنیکی به نام پارامترهای پیش فرض استفاده می کند. این تکنیک به برنامه امکان می دهد تا با تعیین مقدار پیش فرض برای یک یا چند پارامتر تابع، آن ها را در هنگام مقدار دهی اختیار کند. این روش برای افزودن انعطاف پذیری به کد برنامه، بسیار کاربرد دارد. و در زبان برنامه نویسی C، میتوان برای یک پارامتر مقدار پیشفرضی را تعیین کرد که هنگام فراخوانی در صورت ندادن آرگومان مربوط به آن پارامتر با مقدار پیشفرض مقدار بگیرد. این مقدار پیشفرض برای ساده کردن فراخوانی توابع پیچیده و بعضی مواقع به عنوان یک شکل میانبر سربارگذاری تابع استفاده میشوند. در این مبحث در مورد مقادیر پیش فرض برای پارامترها و محدودیت پارامترهای پیش فرض در توابع و همچنین نحوه سربارگذاری توابع در زبان C، می پردازیم.
۱- مقادیر پیش فرض برای پارامترها
در بسیاری از موارد، توابعی داریم ک دارای تعداد زیادی پارامتر هستند که در هر بار فراخوانی باید آرگومانهای متناظر با هریک را به تابع ارسال کرد. چنانچه تعداد آرگومانهای ارسالی، با تعداد پارامترها یکسان نباشد (کمتر یا بیشتر)، یک خطای کامپایل ایجاد می گردد. اما در بعضی موارد، مقادیر بعضی از این پارامترها در اکثر موارد مشخص است و فقط در شرایط خاص تغییر می کند. بعنوان مثال فرض کنید تابعی نوشته اید که یک پنجره را مکان مورد نظر ترسیم میکند. پارامترهای متداول برای چنین تابعی عبارتند از:
مختصات شروع، رنگ زمینه، رنگ متن، نوع حاشیه (یک خطی، دوخطی ) و … اما فرض کنیم پنجره های متداول در برنامه ما دارای رنگ زمینه آبی و رنگ متن سفید با حاشیه دو خطی هستند. در اینصورت در اکثر موارد بجز اطلاعات مربوط به مختصات پنجره، بقیه اطلاعات بصورت تکراری ارسال می گردند. در چنین مواردی می توان از پارامترهای پیش فرض استفاده نمود. چنانچه یک پارامتر از تابع دارای مقدار پیش فرض باشد، آنگاه تابع فراخواننده می تواند هیچ آرگومانی متناظر با این پارامتر ارسال ننماید. در اینصورت تابع فراخوانده شده از مقدار پیش فرض برای آن پارامتر استفاده می نماید. برای تعیین مقدار پیش فرض برای پارامتر، کافی است که در هنگام تعریف پارامتر با استفاده از عملگر نسبت دهی (=) مقدار پیش فرض را به پارامتر نسبت دهیم.
#include <stdio.h> void sum(int a, int b=0, int c=0) { return(a+b+c); } void main() { printf("sum(5,10,20) = %d \n", sum(5,10,20) ); printf("sum(5,10) = %d \n", sum(5,10) ); printf("sum(5) = %d \n", sum(5) ); }
خروجی کد بالا:
sum(5,10,20) = 35 sum(5,10) = 15 sum(5) = 5
همانطور که دیده می شود، در اولین فراخوانی، تابع sum با ۳ آرگومان فراخوانی شده و در نتیجه حاصل جمع آنها را بازگردانده است. اما در دومین فراخوانی فقط دو آرگومان ارسال شده و در نتیجه پارامتر سوم یعنی، c از مقدار پیش فرض خود یعنی صفر استفاده نموده است و حاصل جمع دو عدد بعنوان خروجی باز گردانده شده است. در فراخوانی سوم، تنها یک آرگومان ارسال شده و پارامترهای b و c از مقدار پیش فرض خود یعنی صفر، استفاده نموده اند و بنابراین تنها خود عدد ارسالی بعنوان خروجی بازگردانده شده است. بنابراین با توجه به تعریف فوق، می توان تابع sum را با سه، دو و یا یک آرگومان فراخوانی کرد.
۱-۱- محدودیت در نحوه استفاده از پارامترهای پیش فرض
در نحوه استفاده از پارامترهای پیش فرض دو محدودیت وجود دارد:
- تعریف پارامترهای پیش فرض حتما باید از سمت راست ترین پارامتر آغاز شده و به سمت چپ ادامه یابد. بعنوان نمونه در مثال فوق چنانچه پارامتر c مقدار پیش فرض نداشته باشد، پارامتر b نیز قادر به اعلام مقدار پیش فرض نیست. علاوه براین پارامتر a نیز فقط درصورتی می تواند مقدار پیش فرض داشته باشد که پارامترهای b و c هر دو دارای مقدار پیش فرض باشند. یعنی اعلان زیر خطا می باشد:
int sum(int a=0, int b, int c=0) // compile error
- در هنگام فراخوانی یک تابع که دارای پارامترهای پیش فرض است، آرگومانهای ارسالی از چپ به راست به پارامترها اختصاص می یابند. یعنی در صورتیکه هنگام فراخوانی تابع sum دو آرگومان به آن ارسال شود، اولی به a و دومی به b تخصیص خواهد یافت. تحت هیچ شرایطی نمی توان بدون اینکه مقداری برای b ارسال شود، آرگومانی را برای c ارسال نمود.
۲- سربارگذاری توابع
در برخی موارد، تابعی داریم که یک وظیفه خاص را برای چندین نوع داده مختلف انجام می دهد. بعنوان مثال تابع max را درنظر بگیرید که دو داده را بعنوان ورودی دریافت و حداکثر آنها را باز می گرداند. چنانچه این تابع را برای دو ورودی از نوع عدد صحیح بنویسیم، آنگاه برای ورودی های اعشاری درست عمل نخواهد کرد. بنابراین ممکن است برنامه نویس ترجیح دهد دو نسخه از این تابع داشته باشد: یکی برای اعداد صحیح و یکی برای اعداد اعشاری. اما از آنجا که نمی توان دو شناسه همنام تعریف کرد، بنابراین ممکن است مجبور شویم از دو نام مجزا استفاده نماییم، مانند intMax برای اعداد صحیح و doubleMax برای اعداد اعشاری.
خوشبختانه با استفاده از سربارگذاری توابع، می توان این مشکل را حل کرد. با استفاده از سربارگذاری، می توان توابعی تعریف کرد که دارای نام یکسان باشند، ولی لیست پارامترهای ورودی آنها متفاوت باشد. در اینصورت در هنگام فراخوانی تابع، زبان برنامه نویسی C با توجه به نوع آرگومانهای ارسالی، تابع مناسب را انتخاب کرده و فراخوانی می نماید. تفاوت در لیست پارامترهای ورودی توابع سربارگذاری شده، می تواند شامل یک یا هر دو مورد زیر باشد:
– تفاوت در تعداد پارامترها
– تفاوت در نوع داده یک یا چند پارامتر
بعنوان مثال، می توانیم دو تابع max داشته باشیم که اولی دو عدد صحیح و دومی دو عدد اعشاری دریافت نمایند. علاوه براین می توان تابع max سومی نیز نوشت که ۳ عدد صحیح دریافت و حداکثر آ«ها را بازگرداند.
#include <stdio.h> int max(int a, int b) { if (a > b) return(a); else return(b); } double max(double a, double b) { if (a > b) return(a); else return(b); } int max(int a, int b, int c) { if (a > b) if (a > c) return(a); else return(c); else if (b > c) return(b);else return(c); } void main() { printf("max(8, 10) = %d \n", max(8, 10) ); printf("max(4.23, 3.712) = %f \n", max(4.23, 3.712) ); printf("max(15, 3, 20) = %d \n", max(15, 3, 20) ); }
خروجی کد بالا:
max(8, 10) = 10 max(4.23, 3.712) = 4.23 max(15, 3, 20) = 20
توضیح مثال: همانگونه که در مثال دیده می شود، ۳ تعریف مختلف از تابع max با ورودی های مختلف ارائه شده است. با فراخوانی تابع ، max خود زبان C بسته به نوع آرگومانهای ارسالی، تابع مناسب را تشخیص داده و آن را فراخوانی می نماید.
int maximum (int num1, int num2) { if (num1 > num2) { return num1; } else { return num2; } } float maximum (float num1, float num2) { if (num1 > num2) { return num1; } else { return num2; }
خروجی کد بالا:
maximum (10, 20); maximum (10.2f, 43.56f);
به پایان مبحث مقادیر پیش فرض برای پارامترها و نحوه سربارگذاری توابع در زبان C، رسیدیم. به یاد داشته باشید، که سربارگذاری نمی تواند بر اساس نوع داده خروجی انجام شود. بعبارت دیگر چنانچه دو تابع همنام با لیست پارامترهای یکسان داشته باشیم که تنها نوع مقدار خروجی آن دو متفاوت باشد، یک خطای کامپایل مبنی بر استفاده از شناسه های یکسان دریافت خواهیم کرد.