در کد برنامه نویسی C++ بالا ما برای کلاس CExample که دارای یک تابع سازنده تعریفی توسط ما با 2 پارامتر ورودی است 2 شی تعریف کرده ایم. دستور ایجاد شی در سطر 9 نادرست است زیرا تابع سازنده این کلاس دارای 2 پارامتر است که در سطر 5 تعریف شده و در حین ایجاد شی از کلاس باید مقداردهی شوند و دیگر کامپایلر مبنا را فرض خود در نظر نمی گیرد و بر اساس کد ما عمل می نماید .
اشاره گرها همانطور که می توانند به متغیرها اشاره کنند، می توانند به اشیاء یک کلاس نیز اشاره کنند و چون شی نمونه ای از کلاس است پس به کلاس اشاره می کنند .
در حالت ساده برای دسترسی به اعضای کلاس توسط شی تعریفی، از نقطه (.) استفاده کردیم. اما در اشاره گر به شی باید از ترکیب 2 کاراکتر خط و بزرگتر (<-) استفاده کنیم. با هم مثالی کامل از اشاره گر به شی یا همان کلاس را بررسی می کنیم :
در حالت ساده برای دسترسی به اعضای کلاس توسط شی تعریفی، از نقطه (.) استفاده کردیم. اما در اشاره گر به شی باید از ترکیب 2 کاراکتر خط و بزرگتر (<-) استفاده کنیم. با هم مثالی کامل از اشاره گر به شی یا همان کلاس را بررسی می کنیم :
#include <iostream.h>
#include <conio.h>
class CRectangle
{
int width, height;
public:
void set_values (int, int);
int area (void) {return (width * height);}
};
void CRectangle::set_values (int a, int b)
{
width = a;
height = b;
}
int main()
{
CRectangle a, *b, *c;
CRectangle * d = new CRectangle[2];
b= new CRectangle;
c= &a;
a.set_values (1,2);
b->set_values (3,4);
d->set_values (5,6);
d[1].set_values (7,8);
cout « "a area: " « a.area() « endl;
cout « "*b area: " « b->area() « endl;
cout « "*c area: " « c->area() « endl;
cout « "d[0] area: " « d[0].area() « endl;
cout « "d[1] area: " « d[1].area() « endl;
delete[] d;
delete b;
return 0;
}
#include <conio.h>
class CRectangle
{
int width, height;
public:
void set_values (int, int);
int area (void) {return (width * height);}
};
void CRectangle::set_values (int a, int b)
{
width = a;
height = b;
}
int main()
{
CRectangle a, *b, *c;
CRectangle * d = new CRectangle[2];
b= new CRectangle;
c= &a;
a.set_values (1,2);
b->set_values (3,4);
d->set_values (5,6);
d[1].set_values (7,8);
cout « "a area: " « a.area() « endl;
cout « "*b area: " « b->area() « endl;
cout « "*c area: " « c->area() « endl;
cout « "d[0] area: " « d[0].area() « endl;
cout « "d[1] area: " « d[1].area() « endl;
delete[] d;
delete b;
return 0;
}
همانطور که می بینید در قطعه کد برنامه نویسی C++ در خطوط 4 الی 10 تابعی با نام CRectangle بهمراه متغیرها و توابع عضوش تعریف شده است. تعریف تابع عضو کلاس در خطوط 12 الی 16 صورت گرفته و بدنه اصلی برنامه از سطر 18 شروع می شود .
در سطر 20 ما 3 شی از کلاس ایجاد کرده ایم که شی a معمولی و اشیاء b,c از نوع اشاره گر میباشند. در سطر 21 شیئی از نوع اشاره گر بنام d تعریف شده که به دو شی از کلاس CRectangle که بصورت آرایه در نظر گرفته اشاره می نماید. در واقع d شی اشاره گری است که به محل قرارگیری دو شی از کلاس اشاره می کند. و در سطر 22 نیز از کلاس یک شی ایجاد کردیم که به آن با استفاده از کلمه کلیدی new فضایی در حافظه اختصاص داده شده است .
در سطر 23 شی c حاوی آدرس شی a است پس می توان گفت که هر تغییری در a در c هم اعمال خواهد شد. در سطر 24 شی a از تابع عضو کلاس بنام set_values استفاده می کند و پارامترهای 1و2 را به آن می دهد. چون a یک شی معمولی از کلاس است پس برای بکارگیری آن از نقطه استفاده کردیم. اما در سطرهای 25 و26 چون از اشیائی که اشاره گر هستند استفاده کرده ایم پس با استفاده از عملگر مخصوص (->) آنها را به تابع عضو کلاس ربط می دهیم .
در سطر 20 ما 3 شی از کلاس ایجاد کرده ایم که شی a معمولی و اشیاء b,c از نوع اشاره گر میباشند. در سطر 21 شیئی از نوع اشاره گر بنام d تعریف شده که به دو شی از کلاس CRectangle که بصورت آرایه در نظر گرفته اشاره می نماید. در واقع d شی اشاره گری است که به محل قرارگیری دو شی از کلاس اشاره می کند. و در سطر 22 نیز از کلاس یک شی ایجاد کردیم که به آن با استفاده از کلمه کلیدی new فضایی در حافظه اختصاص داده شده است .
در سطر 23 شی c حاوی آدرس شی a است پس می توان گفت که هر تغییری در a در c هم اعمال خواهد شد. در سطر 24 شی a از تابع عضو کلاس بنام set_values استفاده می کند و پارامترهای 1و2 را به آن می دهد. چون a یک شی معمولی از کلاس است پس برای بکارگیری آن از نقطه استفاده کردیم. اما در سطرهای 25 و26 چون از اشیائی که اشاره گر هستند استفاده کرده ایم پس با استفاده از عملگر مخصوص (->) آنها را به تابع عضو کلاس ربط می دهیم .
اگر دقت کنید می بینید که در سطر 21 ما شی اشاره گر d را بعنوان آرایه ای با طول 2 در نظر گرفته ایم پس دستور سطر 26 فقط به آدرس آن آرایه یعنی اولین خانه اشاره می کند. اما در سطر 27 ما دومین عضو آرایه که خود یک شی از کلاس است را به تابع عضو ربط دادیم به همین علت آنرا دیگر اشاره گر در نظر نمیگیریم و مانند یک شی معمولی از نقطه برای استفاده از کلاس عضو استفاده می کنیم .
در سطرهای 28 الی 32 ما با استفاده از دستور خروجی cout نتایج مورد نظر را در خروجی نمایش می دهیم و در انتها باید اشیائی را که با استفاده از کلمه کلیدی new ایجاد کرده ایم و به آنها در حافظه فضا اختصاص دادیم را با استفاده از کلمه کلیدی delete پاک کرده و فضاهای آنها را به حافظه برگردانیم .
در سطرهای 28 الی 32 ما با استفاده از دستور خروجی cout نتایج مورد نظر را در خروجی نمایش می دهیم و در انتها باید اشیائی را که با استفاده از کلمه کلیدی new ایجاد کرده ایم و به آنها در حافظه فضا اختصاص دادیم را با استفاده از کلمه کلیدی delete پاک کرده و فضاهای آنها را به حافظه برگردانیم .
نکته ) عزیزان باید بادقت کد را مورد مطالعه قرار دهند و مفاهیم فصول قبل مثل اشاره گرها، توابع، آرایه ها و دیگر موارد را درک کرده باشند تا به راحتی قطعه برنامه C++ بالا را تجزیه و تحلیل نمایند .
قبلا یادآوری شد که اعضای یک کلاس اعم از داده ها یا توابع دارای 3 نوع سطح دسترسی می باشند که شامل دسترسی خصوصی private و دسترسی عمومی public و دسترسی حفاظت شده protected است .
اگر داده ها و توابع عضو یک کلاس از نوع private تعریف شوند فقط داده ها و توابع درونی آن کلاس در داخل همان کلاس می توانند به آنها دسترسی داشته باشند و هیچ جزء دیگری در بیرون از کلاس حتی شی ساخته شده از همان کلاس هم اجازه و توانایی دسترسی و کار با آنها را ندارند مگر تابعی را تعریف نماییم که در اصطلاح دوست(Friend) کلاس مورد بحث باشد .
پس تابع دوست یک کلاس، تابع ویژه ای است که می تواند به تمامی اعضای کلاس حتی اعضای private نیز دسترسی داشته باشد. تفاوتی نمی کند که تابع دوست کلاس را عمومی یا خصوصی تعریف نماییم. یک تابع دوست کلاس طبق الگوی زیر تعریف می شود که باید از کلمه کلیدی friend در ابتدای آن استفاده نمود :
مثالی ابتدایی از تعریف تابع دوست کلاس و نحوه بکارگیری آن در کلاس را بررسی می نماییم :
class Accumulator
{
private:
int m_nValue;
public:
Accumulator() { m_nValue = 0; }
void Add(int nValue) { m_nValue += nValue; }
// Make the Reset() function a friend of this class
friend void Reset(Accumulator &cAccumulator);
};
// Reset() is now a friend of the Accumulator class
void Reset(Accumulator &cAccumulator)
{
// And can access the private data of Accumulator objects
cAccumulator.m_nValue = 0;
}
{
private:
int m_nValue;
public:
Accumulator() { m_nValue = 0; }
void Add(int nValue) { m_nValue += nValue; }
// Make the Reset() function a friend of this class
friend void Reset(Accumulator &cAccumulator);
};
// Reset() is now a friend of the Accumulator class
void Reset(Accumulator &cAccumulator)
{
// And can access the private data of Accumulator objects
cAccumulator.m_nValue = 0;
}
مانگونه که در کد برنامه نویسی C++ بالا ملاحظه می فرمایید در سطر 9 برای کلاس Accumulator، تابع دوستی بنام Reset تعریف شده که دارای پارامتری ورودی که یک شی از خود کلاس است می باشد .
در سطر 4 متغیری private بنام m_nValue تعریف شده است که فقط در داخل کلاس خود می توان به آن دسترسی داشت و در خارج از کلاس هر نوع دسترسی به این متغیر خصوصی منجر به خطا خواهد گشت مگر اینکه از یک تابع دوست کلاس برای این منظور استفاده کنیم که صحت دسترسی را در بیرون از کلاس Accumulator و در سطر 15 از کد فوق مشاهده می کنیم .
در سطر 4 متغیری private بنام m_nValue تعریف شده است که فقط در داخل کلاس خود می توان به آن دسترسی داشت و در خارج از کلاس هر نوع دسترسی به این متغیر خصوصی منجر به خطا خواهد گشت مگر اینکه از یک تابع دوست کلاس برای این منظور استفاده کنیم که صحت دسترسی را در بیرون از کلاس Accumulator و در سطر 15 از کد فوق مشاهده می کنیم .
نکته ) دقت کنید که برای تعریف بدنه و عملکرد یک تابع دوست کلاس دیگر نیازی به استفاده از عملگر :: به همراه نام کلاس نمی باشد در صورتیکه قبلا توضیح داده شد برای تعریف تابع عضو کلاس در بیرون از آن کلاس باید نام کلاس بهمراه عملگر :: ذکر شود .
#include <iostream.h>
#include <conio.h>
class base
{
int val1,val2;
public:
void get()
{
cout « "Enter two values:";
cin » val1 » val2;
}
friend float mean(base ob);
};
float mean(base ob)
{
return float(ob.val1+ob.val2)/2;
}
void main()
{
clrscr();
base obj;
obj.get();
cout « "\n Mean value is : " « mean(obj);
getch();
}
#include <conio.h>
class base
{
int val1,val2;
public:
void get()
{
cout « "Enter two values:";
cin » val1 » val2;
}
friend float mean(base ob);
};
float mean(base ob)
{
return float(ob.val1+ob.val2)/2;
}
void main()
{
clrscr();
base obj;
obj.get();
cout « "\n Mean value is : " « mean(obj);
getch();
}
در برنامه C++ بالا کلاسی بنام base وجود دارد که دارای 2 متغیر عضو private از نوع int و تابعی بنام get که دارای پارامتر ورودی نیست و دسترسی public برایش تعریف شده و یک تابع دوست کلاس بنام mean که نوع دسترسی آن مهم نیست و نوع بازگشتی float را برمیگرداند و دارای یک پارامتر ورودی است که شیئی از همان کلاس base میباشد .
بدنه تابع دوست کلاس از سطر 16 تا 19 در خارج از کلاس تعریف شده و براحتی و با ساخت یک شی بنام ob به متغیرهای عضو private کلاس base دسترسی دارد که میانگین دو عدد ورودی را محاسبه می نماید. در سطر 18 ما از اصل تبدیل نوع (Type Casting) برای جلوگیری از بروز خطای محاسباتی در نتایج برنامه استفاده کردیم. در واقع ما با استفاده از اصل تبدیل نوع به کامپایلر اعلام می کنیم که هرچند متغیرهای اولیه از نوع int هستند اما حاصل نتیجه را به صورت float و بدون گرد کردن و با قسمت اعشارش می خواهیم .