همانطور که مشاهده کردید در کلاس بالا تابع set_Values() وظیفه مقدار دادن به متغیر ها که همان عرض و طول یک چهار ضلعی هستند را بر عهده داشت. اما در کلاس تابعی بنام سازنده کلاس وجود دارد که کار مقداردهی اولیه به متغیرهای لازم را انجام می دهد .
تابع سازنده، تابع عضو ویژه ای است هم نام با نام کلاس که نوع بازگشتی ندارد و حتی از نوع void هم نیست اما می تواند پارامتر ورودی داشته باشد و دارای دسترسی public می باشد .
هنگامی که از کلاس مربوطه شی ایجاد می شود، تابع سازنده به متغیرهای مربوطه مقدار تعیین شده و فضایی در حافظه را اختصاص می دهد. این کار باعث می شود که از مقداردهی متغیرها و تهی نبودن آنها اطمینان حاصل شود .
تابع سازنده، تابع عضو ویژه ای است هم نام با نام کلاس که نوع بازگشتی ندارد و حتی از نوع void هم نیست اما می تواند پارامتر ورودی داشته باشد و دارای دسترسی public می باشد .
هنگامی که از کلاس مربوطه شی ایجاد می شود، تابع سازنده به متغیرهای مربوطه مقدار تعیین شده و فضایی در حافظه را اختصاص می دهد. این کار باعث می شود که از مقداردهی متغیرها و تهی نبودن آنها اطمینان حاصل شود .
وقتی که کار با شی مورد نظر تمام شد بهتر است که فضایی را که در حافظه به متغیرهای عضو کلاس توسط تابع سازنده یا مولد داده شده است را آزاد کنیم که اینکار را با استفاده از تابع عضو ویژه دیگری بنام تابع مخرب انجام می دهیم. این تابع نیز دارای ویژگیهای تعریفی تابع سازنده است با این تفاوت که با علامت ~ در ابتدای آن تعریف می گردد .
👍1
در ادامه به نحوه تعریف و استفاده از توابع عضو سازنده و مخرب در کلاس می پردازیم :
#include <iostream.h>
#include <conio.h>
class CRectangle
{
int *width, *heigth;
public:
CRectangle(int, int);
~CRectangle();
int area() { return (*width * *heigth);}
};
CRectangle :: CRectangle(int a, int b)
{
width = new int;
heigth = new int;
*width = a;
*heigth = b;
}
CRectangle :: ~CRectangle()
{
delete width;
delete heigth;
}
void main()
{
CRectangle rect1(3,4), rect2(5,6);
cout « "rect1 area = " « rect1.area() « "\n";
cout « "rect2 area = " « rect2.area();
getch();
}
#include <conio.h>
class CRectangle
{
int *width, *heigth;
public:
CRectangle(int, int);
~CRectangle();
int area() { return (*width * *heigth);}
};
CRectangle :: CRectangle(int a, int b)
{
width = new int;
heigth = new int;
*width = a;
*heigth = b;
}
CRectangle :: ~CRectangle()
{
delete width;
delete heigth;
}
void main()
{
CRectangle rect1(3,4), rect2(5,6);
cout « "rect1 area = " « rect1.area() « "\n";
cout « "rect2 area = " « rect2.area();
getch();
}
خوب، تابع مولد (سازنده) کلاس در سطر 8 از برنامه و تابع مخرب کلاس هم در سطر بعدی تعریف شده اند. سطرهای 13 تا 25 نحوه رفتار این دو تابع عضو کلاس را بیان می کنند. دقت فرمایید که دو متغیر عضو کلاس از نوع اشاره گر تعریف شده اند، پس برای کار با آنها در تابع سازنده کلاس باید متغیرهایی از نوع اشاره گر داشته باشیم که این کار را در سطرهای 15و16 انجام داده ایم .
با استفاده از کلمه کلیدی new می توان یک object یا همان شی را تعریف نماییم. یک شی این قابلیت را دارد که هر نوعی را بگیرد (این را از مفهوم شی گرایی درک کردیم!). پس بعد از تعریف شی های width, height آنها را اشاره گر در نظر میگیریم (سطرهای 17و18) .
کلمه کلیدی delete که در سطرهای 23و24 بکار رفته است دستوری است برای آزادسازی حافظه اشغالی توسط هر شی یا متغیر ، ... در برنامه .
ادامه برنامه کاملا واضح است .
با استفاده از کلمه کلیدی new می توان یک object یا همان شی را تعریف نماییم. یک شی این قابلیت را دارد که هر نوعی را بگیرد (این را از مفهوم شی گرایی درک کردیم!). پس بعد از تعریف شی های width, height آنها را اشاره گر در نظر میگیریم (سطرهای 17و18) .
کلمه کلیدی delete که در سطرهای 23و24 بکار رفته است دستوری است برای آزادسازی حافظه اشغالی توسط هر شی یا متغیر ، ... در برنامه .
ادامه برنامه کاملا واضح است .
مانند سربارگذاری توابع، سازنده های کلاس را نیز میتوان با نامهای مشابه ولی با آرگومانهای متفاوت سربار نمود که در زیر نمونه ای را به همراه هم خواهیم دید :
#include <iostream.h>
#include <conio.h>
class CRectangle
{
int width,heigth;
public:
CRectangle();
CRectangle(int, int);
int area(void) { return (width*heigth);}
};
CRectangle :: CRectangle()
{
width = 5;
heigth = 5;
}
CRectangle :: CRectangle(int a, int b)
{
width = a;
heigth = b;
}
void main()
{
CRectangle rect1(3,4);
CRectangle rect2;
cout « "rect1 area = " « rect1.area() « "\n";
cout « "rect2 area = " « rect2.area();
getch();
}
#include <conio.h>
class CRectangle
{
int width,heigth;
public:
CRectangle();
CRectangle(int, int);
int area(void) { return (width*heigth);}
};
CRectangle :: CRectangle()
{
width = 5;
heigth = 5;
}
CRectangle :: CRectangle(int a, int b)
{
width = a;
heigth = b;
}
void main()
{
CRectangle rect1(3,4);
CRectangle rect2;
cout « "rect1 area = " « rect1.area() « "\n";
cout « "rect2 area = " « rect2.area();
getch();
}
نکته) به سطر 28 توجه نمایید که دیگر از پرانتز باز و بسته استفاده نمی کنیم و در صورت استفاده، کامپایلر از برنامه خطا خواهد گرفت (برخلاف سربارگذاری در توابع) .
هنگامی که برای یک کلاس تابع سازنده ای تعریف نکنیم، کامپایلر بطور پیش فرض، فرض می کند که کلاس سازنده ای دارد اما بدون پارامتر. به همین دلیل است که وقتی کلاسی بدون تابع سازنده را تعریف می کنیم می توانیم از آن یک شی ایجاد کنیم که کار تعریف تابع سازنده را خود کامپایلر انجام میدهد .
class CExample
{
public:
int a, b, c;
void multiply (int n, int m) { a=n; b=m; c=a*b; }
};
CExample ex;
{
public:
int a, b, c;
void multiply (int n, int m) { a=n; b=m; c=a*b; }
};
CExample ex;
همانطور که در کد برنامه نویسی C++ بالا می بینیم برای کلاس هیچگونه تابع سازنده ای تعریف نشده اما میتوان از کلاس CExample یک شی بنام ex ایجاد نمود و در طول برنامه از آن استفاده کرد و تنها دلیل این موضوع فرض کامپایلر بر وجود یک تابع سازنده بدون پارامتر در کلاس است .
اما اگر خود برای کلاس تابع سازنده ای را تعریف کنیم دیگر کامپایلر فرضی را در نظر نگرفته و بر مبنای تابع سازنده تعریفی ما عمل خواهد کرد مانند کد زیر :
اما اگر خود برای کلاس تابع سازنده ای را تعریف کنیم دیگر کامپایلر فرضی را در نظر نگرفته و بر مبنای تابع سازنده تعریفی ما عمل خواهد کرد مانند کد زیر :
class CExample
{
public:
int a, b, c;
CExample (int n, int m) { a=n; b=m; };
void multiply () { c=a*b; };
};
CExample ex; //نادرست
CExample ex(2,8); //درست
{
public:
int a, b, c;
CExample (int n, int m) { a=n; b=m; };
void multiply () { c=a*b; };
};
CExample ex; //نادرست
CExample ex(2,8); //درست
در کد برنامه نویسی 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;
}