با بخش دوازدهم از سری آموزش ++C در خدمتتون هستیم. پس از معرفی مفهوم و کاربرد کلاس در قسمت قبل، در این قسمت راجع به مفهوم مهمی بنام سازنده در c++ یا Constructor صحبت میکنیم. با ما همراه شوید.?
سازنده چیست؟
همان مثال آموزش یازدهم را در نظر بگیرید. ما یک کلاس به نام Person داریم که 2 فیلد و یک متد دارد. در آموزش قبل ما فیلدهای شیء ساخته شده از Person را بصورت زیر مقداردهی کردیم.
1 2 3 4 5 6 7 8 9 10 11 12 |
int main() { Person p1, p2; p1.name = "Ahmad"; p1.age = 36; p2.name = "Reza"; p2.age = 14; getchar(); return 0; } |
سازنده همانطور که از نام آن پیداست، برای مقداردهی اولیه شیء استفاده میشود. در واقع سازنده در c++ یک متد است که دقیقا همنام با اسم کلاس است. شایان ذکر است که در نوشتن سازنده مقدار خروجی مشخص نمیشود اما میتوان پارامتر ورودی به آن ارسال کرد.
کاربرد سازنده در c++
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
class Person { public: int age; std::string name; std::string WhoAreYou(); Person(int a, std::string n); }; std::string Person::WhoAreYou() { std::string answer; answer = "I am " + name + " and I have " + std::to_string(age) + " years old."; return answer; } Person::Person(int a, std::string n){ age = a; name = n; } |
به کلاس Person سازندهای اضافه کردیم که دو پارامتر ورودی میگیرد. یکی a از نوع int و دیگری n از نوع string. در بدنهی سازنده مقدار age را برابر a و مقدار name را برابر n قرار دادیم. با این کار به نوعی فیلدهای داخل شیء را مقداردهی کردیم. اما برای چگونگی استفاده از سازنده در c++ به کد زیر توجه کنید:
1 2 3 4 5 6 7 8 9 10 11 12 |
int main() { Person p1 = Person(36, "Ahmad"); Person p2 = Person(14, "Reza"); cout << p1.WhoAreYou() << endl; cout << p2.WhoAreYou() << endl; getchar(); return 0; } |
1 2 3 |
I am Ahmad and I have 36 years old. I am Reza and I have 14 years old. |
چون سازنده را تعریف کردیم، پس با تعریف یک شیء از کلاس باید مقداردهی اولیه شود در غیر این صورت برنامه کامپایل نمیگردد. برای مقداردهی اولیه باید نام سازنده که همان نام کلاس است نوشته شود و مانند یک متد پارامترهای ورودی به آن ارسال گردد. با این کار عملیات داخل سازنده اجرا شده و طبق کدی که داخل آن نوشتیم، فیلدهای age و name مقدار میگیرند.
نکته: در صورتی که در بدنه کلاس سازنده گنجانده نشود، سازنده پیش فرض اجرا خواهد شد. در این صورت با تعریف یک شیء از کلاس، بلافاصله سازنده پیش فرض اجرا شده و دیگر احتیاجی به نوشتن آن نیست.
کلمه کلیدی new
یکبار دیگر مقداردهی اولیه شیء که توسط سازنده انجام میشود را مرور میکنیم:
1 2 |
Person p1 = Person(36, "Ahmad"); |
ما شیء p1 را از کلاس Person ساختیم و مقدار اولیه (Person(36, “Ahmad را به آن دادیم. اما با به کارگیری کلمه new قبل از سازنده دو اتفاق مهم رخ میدهد:
- شیء ساخته شده در فضای Heap قرار میگیرد. فضای Heap قسمتی از رم است که CPU کنترلی بر روی آن ندارد و مدیرت آن توسط برنامه نویس انجام میشود. همچنین اگر هر شیای داخل یک بلاک با این روش مقداردهی شود، با به پایان رسیدن آن بلاک مقدار آن از بین نمیرود.
- پس از ساخته شدن شیء در فضای Heap، آدرس شیء برگردانده میشود. با این تفسیر باید هنگام تعریف، شیء را بصورت اشارهگر معرفی نمود.
1 2 |
Person *p1 = new Person(36, "Ahmad"); |
در خط فوق یک اشارهگر به Person با نام p1 معرفی کردیم. سپس با صدا زدن سازنده و کلمه کلیدی new یک شیء از Person در فضای Heap ساختیم که آدرس آن درون p1 قرار میگیرد. دقت شود که p1 اشاره گری به شیء ساخته شده است، نه خود آن. مثال:
1 2 3 4 5 6 7 8 9 10 11 12 |
int main() { Person *p1 = new Person(36, "Ahmad"); Person p2 = Person(14, "Reza"); cout << p1->WhoAreYou() << endl; cout << p2.WhoAreYou() << endl; getchar(); return 0; } |
1 2 3 |
I am Ahmad and I have 36 years old. I am Reza and I have 14 years old. |
چون p1 از نوع اشارهگر است، دسترسی به فیلدها و متدهای آن با علامت <- انجام میشود. در صورتی که p2 چون دقیقا خود شیء است، دسترسی به اعضای آن با نقطه میسر است.
کلمه کلیدی this
اکثر اوقات داخل یک متد در کلاس، پارامتر ورودی متد یا متغیری که داخل متد تعریف شده است، دقیقا همنام با یکی از فیلدهای کلاس است. به کد زیر دقت کنید:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class Person { public: int age; std::string name; std::string WhoAreYou(); Person(int a, std::string n); }; Person::Person(int age, std::string name){ this->age = age; this->name = name; } |
در برنامه بالا متغیر age هم داخل کلاس وجود دارد و هم نام یکی از پارامترهای ورودی سازنده است. اگر بصورت age از آن استفاده کنیم، کامپایلر پارامتر ورودی را منظور میکند و اگر قبل از age کلمه کلیدی this را به همراه <- به کار ببریم به فیلد age که مربوط به کلاس است اشاره میکند.
نکته: چون this یک اشارهگر به شیء است، با توضیحات ارائه شده نتیجه میگیریم که راه دسترسی به آن علامت <- است.
این آموزش هم به پایان رسید و امیدوارم مفید بوده باشه. در مطلب بعدی آموزش به مبحث سطوح دسترسی میپردازیم ?