توابع دوست کلاسها از جمله موارد بحث برانگیز برنامهنویسی شیءگرا به زبان ++C هستند. چرا که یکی از اصول اساسی شیءگرایی، یعنی پنهانسازی اطلاعات، را نقض میکنند. با این وجود به خاطر کاربردهای متعددی که دارند از حضورشان نمیتوان چشمپوشی کرد.
به زبان ساده، توابع دوست یک کلاس توابعی هستند که عضو کلاس نیستند، اما به تمامی دادهها و توابع خصوصی و محافظت شده آن دسترسی دارند.
یک مثال ساده:
کد:
class myclass
{
friend void print_a( myclass );
private:
unsigned a;
public:
myclass( int r )
{
a = r > 0 ? r : - r;
}
void print( )
{
cout << a;
}
};
void print_a( myclass ob )
{
cout << ob.a;
}
void main( )
{
myclass ob( 9 );
ob.print( );
cout << "\t";
print_a( ob );
}
خروجی به این صورت است:
9 9
تابع دوست print_a علیرغم اینکه عضو کلاس myclass نیست، اما به عضو خصوصی a از کلاس دسترسی دارد.
این قطعه برنامه خیلی ساده روش استفاده از توابع دوست را نشان میدهد. توابع دوست با کلمه کلیدی friend در ابتدای تعریفشان مشخص میشوند. توجه داشته باشید که چون این توابع عضو کلاس نیستند نباید عملگر تعیین حوزه ( :: ) زمان تعریف بلوک بدنه آنها استفاده شود. یعنی این عبارت نادرست است:
کد:
void myclass::print_a( myclass ob )
چرا که ممکن است یک تابع، تابع دوست برای چندین کلاس مختلف باشد. درضمن بلوک بدنه این توابع باید بیرون از تعاریف هر کلاسی نوشته شوند.
اما چرا به توابع دوست نیاز داریم؟ چه کاربردهایی دارند که علیرغم نقض آشکار قوانین شیءگرایی از آنها استفاده میشود؟
سربارگذاری عملگرها با توابع دوست:
قبلا در مورد سربازگذاری عملگرها در زبان ++C مطلبی ارائه شده است. در این مطلب تاکید شده بود که برای عملگرهای دودویی (مثل جمع و ضرب و ... ) شیء سمت چپ، تابع عملگر مربوطه را فراخوانی میکند، و شی سمت راست به عنوان آرگومان به تابع ارسال میشود. به عنوان مثال اگر عملگر + برای کلاسی سربارگذاری شده باشد، دو عبارت زیر معادل هم هستند:
کد:
ob1 + ob2 ≡ ob1.operator+( ob2 )
حال فرض کنید کلاسی برای کار با اعداد مختلط با نام comp تعریف کردهایم. عملگر + هم مطابق با عمل جمع اعداد مختلط تعریف شده است. برای جمع زدن یک عدد حقیقی با یک عدد مختلط از تابع + به صورت زیر استفاده میکنیم:
کد:
comp operator + ( double f )
اما این تابع تنها برای جمع عدد حقیقی از سمت راست کاربرد دارد، و نمیتواند از سمت چپ عدد حقیقی را با عدد مختلط جمع کند. به عنوان نمونه، برای یک عدد مختلط مانند c، تابع فوق عبارت c + 3.5 را به خوبی محاسبه میکند. اما اگر جای دو عملوند عوض شود، کاری از دست این تابع بر نمیآید. چرا که در این حالت شیء سمت چپ از جنس خود کلاس نخواهد بود.
اینجاست که تابع دوست به کمک ما میآید. به تعریف زیر دقت کنید:
کد:
friend comp operator + ( double f , comp c )
زمانی که از توابع دوست برای سربارگذاری عملگرهای دودویی استفاده میشود - بر خلاف حالت اصلی - هر دو شیء به صورت آرگومان به تابع ارسال میگردند. آرگومان اول شی سمت چپ و آرگومان دوم شیء سمت راست را مشخص میکند. با تعریف بالا به راحتی عبارت زیر هم محاسبه میشود:
کد کامل این کلاس به این صورت خواهد بود:
کد:
class comp
{
friend comp operator + ( double, comp );
private:
double real, imag;
public:
comp( double r, double i )
{
real = r;
imag = i;
}
comp operator + ( comp r )
{
comp temp( real + r.real, imag + r.imag );
return temp;
}
comp operator + ( double r )
{
comp temp( real + r, imag );
return temp;
}
};
comp operator + ( double l, comp r )
{
comp temp( l + r.real, r.imag );
return temp;
}
تذکر: این تعریف برای کلاس اعداد مختلط به هیچ وجه کامل نیست و تنها قسمت کوچکی از آن را شامل میشود. البته کتابخانههای زبان ++C هم برای کار با اعداد مختلط توابع و کلاسهایی دارند که همه نیازها را برآورده میکنند.
نکته مهم: برای سربارگذاری عملگرهای جریان (یعنی >> و <<) چارهای ندارید جز این که از توابع دوست استفاده کنید (چرا؟).