مفهوم الكلاس class في C++
الكلاس هو عبارة عن نوع جديد يتم تعريفه بواسطة كلمة class و يمكنه أن يحتوي على دوال Functions, متغيرات Variables, مصفوفات Arrays إلخ..
قبل أن نتكلم عن الكلاسات هُناك مفهوم مهم جداً يجب معرفته أولاً و هو التجريد أو ما يسمى Abstraction.
التجريد يعني هو أي شيئ تم تجريده من صفاته و معنى تجريد الكلمة أي خلوها من الزوائد و يحتوي على عناوين فارغة مرتبة بشكل واضح.
الكلاس و فائدة التجريد
لقد تَحدَثنا سابقاً عن المتغيرات في الدروس الأولى و كانت أنواعها (int, char, double, bool, string).
و قٌلنا أنه عندما نقوم بإنشاء متغير جديد فإنه يتم إنشاء مكان خاص لهذا المتغير في الذاكرة و يحمل هذا المتغير اربع خواص و هي (الإسم, القيمة, النوع, عنوان التخزين).
إذا أردنا تخزين قيمة التاريخ مثلا Mar 23 1995 في الذاكرة, فهل التاريخ يمكن التعبير عنه برقم int او double أو string.
كيف يتم تخزين قيمة تاريخ معين في الذاكرة؟
اولاً علينا أن نعرف ما هي الخواص التي نُريد تخزينها في التاريخ, فكل تاريخ به سنة و شهر و يوم.
و من هنا يجب أن نعلم ما هي المتغيرات الذي يجب إنشاءها لأي تاريخ, نحتاج إذاً لثلاثة متغيرات و هي:
- لليوم int day.
- للشهر int month.
- للسنة int year.
و نوع المتغير يكون عددي int, سوف نأخذ مثال لفهم هذا التاريخ اكثر.
الشكل العام للكلاس في C++
class Date{
//تعريف محتويات الكلاس
};
نٌلاحظ أنه بدأنا إسم الكلاس بحرف كبير Capital و هي من العادات الجيدة في البرمجة أن نقوم ببدأ إسم الكلاس بحرف كبير.
حيث يتم تفريقه عن المتغيرات و الفنكشن.
حيث إذا أردنا تعريف متغير نكتبه بالشكل date بحروف صغيرة كعادة برمجية افضل فإن غالب المبرمجين يبدأون إسم الكلاس بحرف كبير.
و في نهاية القوس المعكوف وضعنا فاصلة منقوطة ; في نهاية جسم الدالة بعكس الفنكشن مثل main لا تحتاج لفاصلة بنهاية جسم الدالة.
مثال 1
#include <iostream>
using namespace std;
class Date
{
public:
int year;
int month;
int day;
};
int main ()
{
Date birthday;
birthday.year = 1995;
birthday.month = 3;
birthday.day = 23;
cout << birthday.day << "/" << birthday.month << "/" << birthday.year << endl;
return 0;
}
قُمنا بإنشاء كلاس إسمه Date أي كلاس التاريخ و كان به ثلاث متغيرات عامة و هي للسنة year و للشهر month و لليوم day.
و دخلنا للدالة main و قمنا بتعريف هذا الكلاس على أنه تاريخ ميلاد, وضعنا له الكائن birthday من اجل الوصول لمحتويات الكلاس عن طريقه.
و قمنا بتعيين قيمة للسنة عبر الوصول لها عن طريق الكائن و كانت قيمتها 1995 و بنفس الأمر اسندنا قيمة للشهر و اليوم.
ثم قُمنا ببناء دالة طباعة cout و طلبنا أن تُطبَع لنا في البداية اليوم ثم تفصله بإشارة سلاش / . ثم يطبع الشهر ثم تفصله سلاش ثم يطبع السنة و عند تشغيل هذا الكود ستكون النتيجة هي.
23/3/1995
كما لآحظنا من شاشة التنفيذ السابقةأنه طبع لنا تاريخ الميلاد مثلما طلبنا منه.
مثال 2
قم بإنشاء كلاس عام يحتوي على تاريخي ميلاد مختلفين.
#include <iostream>
using namespace std;
class Date
{
public:
int year;
int month;
int day;
};
int main ()
{
Date birthday;
birthday.year = 1995;
birthday.month = 3;
birthday.day = 23;
cout << birthday.day << "/"<<birthday.month<<"/"<<birthday.year<<endl;
Date birthday2;
birthday2.year = 1994;
birthday2.month = 2;
birthday2.day = 22;
cout << birthday2.day <<"/"<<birthday2.month<<"/"<<birthday2.year<<endl;
return 0;
}
قُمنا بإنشاء كلاس إسمه Date أي كلاس التاريخ و كان به ثلاث متغيرات عامة و هي للسنة year و للشهر month و لليوم day هذا كان في الكلاس.
و دخلنا للدالة main و قمنا بتعريف هذا الكلاس على أنه تاريخ ميلاد وضعنا له الكائن birthday من اجل الوصول لمحتويات الكلاس عن طريقه.
و قمنا بتعيين قيمة للسنة عبر الوصول لها عن طريق الكائن و كانت قيمتها 1995 و بنفس الأمر اسندنا قيمة للشهر و اليوم.
ثم قُمنا ببناء دالة طباعة cout و طلبنا أن تطبَع لنا في البداية اليوم ثم تفصله بإشارة سلاش / ثم يطبع الشهر ثم تفصله سلاش ثم يطبع السنة.
و قُمنا بإنشاء كائن آخر إسمه birthday2 لنصِل لمحتويات الكلاس كما في التاريخ الأول.
و عند تشغيل الكود ستكون نتيجته هي.
23/3/1995
22/2/1994
إستخدام الدوال مع الكلاس
تعرّفنا على الكلاس و قُلنا أنهُ هو طريقة تجريبية لتنسيق البيانات من خلال كتابة المتغيرات المستخدمة.
كما في مثال التاريخ يوجد متغير لليوم و متغير للشهر و متغير للسنة.
لكن ليس هذا كل شيئ يمكن الكلاس فعله أو تخزينه.
يمكن للكلاس تخزين بعض الدوال و التي تكون خاصة فقط لهذا الكلاس و هذا هو مبدأ المكتبات Libraries.
كما في مكتبة math حيت يتم تخزين بعض الدوال في الكلاس ثم يتم إدراج جميع الدوال المخزَّنة في هذا الكلاس.
تعلّمنا كيفية كتابة الكلاس و قُلنا أن المتغيرات الآن (فقط) ستكون عامة public.
و تحت بوبلك نقوم بكتابة جميع المُتغيرات التي نُريدها لأي كائن نقوم بتعريفه من نوع Date.
فعند تعريف كائن جديد على سبيل المثال birthday و عند كتابة إسم الكائن ووضع نقطه بعده. سوف نجِد الإكمال التلقائي قد أتى لنا بجميع المُتغيرات العامة التي وضعناها في الكلاس في الأعلى.
نُلاحظ أنَّ هُناك فرق بين الكائن object و كلاس class, فالكلاس هنا نقوم بتصميم مجرد.
فقط نقوم بكتابة ما هي الخواص المُهِمة لكل تاريخ و كل تاريخ به سنة و شهر و يوم.
فعند إنشاء أي تاريخ سيكون له شهر و يوم و سنة يعني عمل التصميم او القالب.
أما في الكائن فيكون تطبيق القالب أن يكون لدينا كائن حي به قيم للعناصر الذي في الكلاس, فعند تصميم الكلاس. بدون كتابة الكائن فكأنه لا وجود للكلاس في البرنامج الذي نعمل به لأننا لم نقوم بتنفيذ هذا الكلاس.
كعمل مثل تصميم لمنزل لكن لا يوجد منزل على أرض الواقع فقط قُمنا بكتابة عدد الأعمدة الموجودة و طريقة تصميم الأعمدة.
هل طبقّنا هذه الأعمدة على أرض الواقع؟ هل قمت بإنشاء منزل؟ و إن كان الجواب لا فلا وجود للمنزل.
كذلك بالنسبة للكلاس و الكائن إذا لم نقُم بكتابة متغير من نوع الكلاس فإنه لا وجود لهذا الكلاس في الذاكرة, أي لا وجود لمتغير لهذا الكلاس.
بإختصار فإن الكائن هو مُتغير لديه قيم مخزَّنة في الذاكرة فإن الكلاس هو تصميم قالب لأي مُتغير من نوعه.
مثال 3
#include <iostream>
using namespace std;
class Date
{
public:
int year;
int month;
int day;
void print()
{
cout << day << "/" << month<<"/"<<year<<endl; cout
}
};
int main ()
{
Date birthday;
birthday.year = 1995;
birthday.month = 3;
birthday.day = 23;
birthday.print();
Date birthday2;
birthday2.year = 1994;
birthday2.month = 2;
birthday2.day = 22;
birthday2.print();
return 0;
}
قُمنا بإنشاء كلاس إسمه Date أي كلاس التاريخ و كان به ثلاث مُتغيرات عامة و هي للسنة year و للشهر month و لليوم day هذا كان في الكلاس.
و به دالة للطباعة و هي void print من أجل إستدعاءها لطباعة ما نحتاجه و أنشأنا دالة طباعة cout لأجل أن تقوم بطباعة تنسيق هذا الميلاد كيفما نُريد.
و دخلنا للدالة main و قُمنا بتعريف هذا الكلاس على أنه تاريخ ميلاد و وضعنا له الكائن birthday من أجل الوصول لمحتويات الكلاس عن طريقه.
و قُمنا بتعيين قيمة للسنة عبرَ الوصول لها عن طريق الكائن و كانت قيمتها 1995 و بنفس الأمر أسندنا قيمة للشهر و اليوم.
ثم قُمنا بإستدعاء دالة الطباعة print من أجل طباعة الناتج.
و قُمنا بإنشاء كائن آخر إسمه birthday2 لنصِل لمحتويات الكلاس لأجل طباعة الميلاد الثاني.
عند تشغيل هذا الكود ستكون نتيجته هي
23/3/1995
22/2/1994
مثال 4
#include <iostream>
using namespace std;
class Date
{
public:
int year;
int month;
int day;
void print()
{
cout << day << "/" << month << "/" << year << endl;
}
void fill(int d, int m, int y)
{
day = d;
month = m;
year = y;
}
};
int main ()
{
Date birthday;
birthday.fill(23, 3, 1995);
birthday.print();
Date birthday2;
birthday2.fill(22, 2, 1994);
birthday2.print();
return 0;
}
قُمنا بإنشاء كلاس إسمه Date أي كلاس التاريخ و كان به ثلاث مُتغيرات عامة و هي للسنة year و للشهر month و لليوم day هذا كان في الكلاس.
و به دالة للطباعة و هي void print من أجل إستدعاءها لطباعة ما نحتاجه.
و أنشأنا دالة طباعة cout لأجل أن تقوم بطباعة تنسيق هذا الميلاد كيفما نُريد.
ثم أنشأنا الدالة fill و وضعنا بها المُتغيرات و هي d و m و y و عرّفنا إختصارات المُتغيرات أن d يعني اليوم day و m يعني الشهر month و y يعني السنة year.
و قُمنا بالدخول لدالة main و قُمنا بإنشاء كائن خاص بالمواليد و هو birthday ثم عيننا قيم للتاريخ الأول عبر إستدعاء الدالة fill و وضعنا التاريخ الذي يمرر هو 23/3/1995.
و نفس الأمر بالنسبة للمواليد الثاني.
و عند التنفيذ كانت النتيجة هي.
23/3/1995
22/2/1994
دالة البناء Constructor فييي
الكونستركتور ( Constructor ) هو عبارة عن دالة يتم استدعاءها بشكل تلقائي عند إنشاء كائن object من الكلاس.
هذه الدالة تجعلك قادراً على تمرير قيم أولية للكائن مباشرتاً في لحظة إنشائه.
دالة البناء ( Constructor ) هي أول دالة يتم إستدعائها عند إنشاء أي كائن object من أي كلاس.
و من أهم مهام هذه الدالة أنها تقوم بإعطاء قيم اولية لجميع المُتغيرات الموجودة في الكلاس.
صفات دالة البناء كونستركتور Constructor
- لا تقوم بإرجاع قيمة و لا حتى void.
- إسمها يأتي نفس إسم الكلاس (فإذا كان إسم الكلاس Date فيكون إسمها أيضاً Date).
- يتم إستدعائها عند إنشاء أي كائن من الكلاس مباشرتاً.
مثال 5
لنُفكر ماذا يوجد حولنا "هواتف ذكية و يوجد أشخاص" سوف نقوم بعمل كلاس يقوم بحفظ أشخاص. فالشخص لديه إسم و عمر و طول و الطول يُعتبَر مُهم, سوف نقوم بعمل كلاس يحفظ بيانات الشخص.
#include <iostream>
using namespace std;
class Person
{
public:
string name;
int age;
double height;
Person(string n, int a, double h)
{
name = n;
age = a;
height = h;
}
void print()
{
cout << "الأسم " << name << endl;
cout << "العمر" << age << endl;
cout << "الطول" << height << endl;
}
};
int main()
{
Person saja("Saja", 27, 155.7);
saja.print();
return 0;
}
لقد قمنا بإنشاء كلاس إسمه Person و كان به ثلاث متغيرات عامة و هي متغير نصي string من أجل تخزين الإسم فيه. و متغير عددي int لتخزين العمر فيه و متغير بفاصلة عشريه double لتخزين الطول فيه.
ثم قمنا بإنشاء كونستركتر Constructor و أخذ نفس إسم الكلاس Person و عرفنا به المتغيرات الثلاث. بأن المتغير الذي يرمز للإسم نختصره بحرف n و المتغير الذي يرمز للعمر بحرف a و المتغير الذي يرمز للطول h ثم عرّفناهم.
و بعد ذلك قمنا بإنشاء دالة void من أجل الطباعة print عند إستدعائها و وضعنا بأن يطبع لنا على شاشة الإخراج عبر cout أن يطبع الأسم و اسفله العمر و اسفله الطول.
ثم دخلنا بداخل الدالة main و أنشأنا كائن من إسم الكلاس إسمه saja ووضعنا بداخل الأقواس القيم التي سوف يتم إستدعائها و تعيينها للمتغيرات الثلاث.
و إستدعينا دالة الطباعة عن طريق الكائن saja.
و عند تنفيذ هذا البرنامج سوف نحصل على النتيجة الآتية.
Name: Saja
Age: 27
Length: 155.7
كما نلاحظ أنه طبع لنا الإسم Saja في الأعلى ثم العمر 27 ثم الطول 155.7.
مثال 6
قم بكتابة برنامج يكون به كلاس بإسم Car و به أربع متغيرات لإسم السيارة و لونها و سرعتها و تاريخ صنعها.
#include <iostream>
using namespace std;
class Car {
public:
string name;
string color;
int speed;
int model;
Car(string name, string color, int speed, int model)
{
this->name = name;
this->color = color;
this->speed = speed;
this->model = model;
}
void printInfo()
{
cout << "Name: " << name << "\n";
cout << "Color: " << color << "\n";
cout << "Speed: " << speed << "\n";
cout << "Model: " << model << "\n";
}
};
int main()
{
Car car("BMW", "black", 240, 2001);
car.printInfo();
return 0;
}
لقد قمنا بإنشاء كلاس إسمه Car و قمنا بإنشاء اربع متغيرات عامة public و هي:
- متغير نصي لإسم السيارة name.
- متغير نصي آخر للون السيارة color.
- متغير عددي صحيح لسرعة السيارة speed.
- متغير عددي لتاريخ صنعها أو موديلها model.
و قمنا بإنشاء كونستركتور أخذ نفس إسم الكلاس Car و مرّرنا بيانات به من أجل إستدعاءه.
ثم قمنا بوضع القيم التي يجب تمريرها للكونستركتور.
و بعدها قمنا بإنشاء دالة طباعة عن طريق void و الدالة هي printInfo مهمتها طباعة كل قيم المتغيرات الموجودة في الكلاس Car.
و دخلنا لداخل الدالة main قمنا بإشتقاق كائن من الكلاس Car و الكائن هو car و وضعنا به القيم التي يجب تمريرها للكونستركتور بشكل مباشر.
و قمنا بإستدعاء دالة الطباعة عن طريق الكائن.
و عندما قمنا بتشغيل الكود السابق سنحصل على النتيجة.
Name: BMW
Color: black
Speed: 240
Model: 2001
تعريف الدوال خارج الكلاس
سوف نتعلم عن كيفية كتابة الدوال الخاصة بالكلاس خارج الكلاس.
مثال 7
#include <iostream>
using namespace std;
class Student{
private:
string name;
double grade;
public:
Student(string n, double g)
{
setName(n);
setGrade(g);
}
void setName(string n)
{
name = n;
}
void setGrade(int g)
{
grade = g;
}
string pass()
{
return (grade > 60 ? "yes" : "no");
}
void printStatus()
{
cout << "Name : " << name << endl;
cout << "Degree : " << grade << endl;
cout << "Success : " << pass() << endl;
cout << endl;
}
};
int main()
{
Student saja("Saja", 100);
saja.printStatus();
Student data("Mohammad", 30);
data.printStatus();
return 0;
}
لقد قمنا بتعريف كلاس إسمه Student و كان به خاصيتان و هما name أي الإسم و نوعه نصي string و grade أي الدرجة نوعه double.
و كما تعلمنا مسبقاً أن جميع الخواص أو المتغيرات يتم تعريفها كـ private كي لا يتم الوصول إليها. و التعديل على قيمها مباشرتاً من قبل الدوال خارج كلاس Student مثل دالة main.
ثم في public نضع جميع الـ function ( جميع الدوال ) و من ضمن هذه الدوال الأولى هي دالة البناء الكونستركتور.
و قمنا بإعادة تعريف دالة البناء الكونستركتور Student بإضافه معاملين المعامل الأول n و المعامل الثاني g.
كي نقوم بتغير name من خلال إستدعاء دالة setName و هي طريقة افضل لكتابة الكونستركتور أن نقوم بإستعمال setName بدلاً من كتابة name=n.
و ايضاً قُمنا بكتابة setGrade فسيتم تعريف name في n و الـ Grade في g و هما دالتان من نوع void.
و كما قُلنا أن Setters من نوع void و يتم تمرير معامل من نفس نوع المتغير name.
و المتغير name نوعه string فسيتم تمرير string n و يتم تعيين name بهذا المعامل و ايضاً setGrade بنفس الطريقة.
ثم انشأنا دالة تسمى pass و هي تقوم بإرجاع string تقوم هذه الدالة بالتأكد ما إن كان Grade اكبر من 60 سيقوم بطباعة نعم أي ناجح.
و غير ذلك سوف يقوم بطباعة لا أي راسب.
و دالة printStatus هذه الدالة سوف تقوم بطباعة الإسم و الدرجة و الحالة ما إن كان ناجحاً ام لا.
فسيتم طباعة النجاح من الدالة pass و في الدالة main قُمنا بتعريف كائن إسمه saja و كان هذا الكائن يُمرر قيمة Saja كإسم و 100 كدرجة.
ثم سيتم طباعة الحالة عن طريق الكائن.
ثم انشانا كائن data و كان يمرر Mohammad كإسم و 30 كدرجة ثم يقوم بطباعة الحالة له.
Name: Saja
Degree: 100
Success: yes
Name: Mohammad
Degree: 30
Success: no
نُلاحظ أنه عند دالة الطباعة cout لم نكتب Get لأننا لم نقُم بالحاجة إلى إستدعاء Grade لأي من الكائنات.
لنَقُم بإعادة ترتيب الكود السابق, تحدثنا في دروس سابقة عن طريقة كانت بأن نقوم بكتابة رأس الدالة فقط مثلاً.
void printName()
{
هنا نقوم بكتابة الكود
}
و نقوم بنسخ الكود و لصقه أسفل main, فهل يمكننا فعل ذلك بدوال الكلاس؟
سوف نُلاحظ أن دوال الكلاس كبيرة بعض الشيئ و قد يكون في بعض الكلاسات دوال كثيرة و كبيرة ايضاً.
هل يمكننا إختصار ذلك؟ نعم يُمكننا بكل بساطة سوف نقوم بنسخ جميع الدوال الذي في public في المثال السابق و لصقها خارج الـ main.
حيث أن main غير معرًّفة خارجها لأن هذا النطاق خارج جميع الدوال و خارج الكلاس ايضاً.
لكن نحن نُريد تحديد مثلاً دالة setName تنتمي إلى الكلاس Student بكل بساطة يمكننا كتابة.
Student::Student(string n, double g)
بهذه الطريقة يُمكننا الوصول إلى الدوال التي قُمنا بتعريفها.
نقوم في الأعلى بإلغاء جميع أجسام الدوال و نقوم فقط بإبقاء رؤوس الدوال بإضافة الفاصله المنقوطة.
كما كنا نفعل سابقاً أعلى main فهذا يسمى function prototype أي راس الدوال بحيث فقط نقوم بإبقاء رؤوس العناوين لبعض الدوال.
و خارج الكلاس نقوم بتعريف هذه الدوال لذلك يجب كتابة Student نقطتين فوق بعض أي سوف نقوم. بإكمال بعض الدوال الخاصة بالكلاس Student و سيسمح لنا بكتابة إسم الدالة.
سيكون الكود بالشكل.
#include <iostream>
#include <iomanip>
using namespace std;
class Student{
private:
string name;
double grade;
public:
Student(string n, double g);
void setName(string n);
void setGrade(int g);
string pass();
void printStatus();
};
int main()
{
Student saja("Saja", 100);
saja.printStatus();
Student data("Mohammad", 30);
data.printStatus();
return 0;
}
Student::Student(string n, double g)
{
setName(n);
setGrade(g);
}
void Student::setName(string n)
{
name = n;
}
void Student::setGrade(int g)
{
grade = g;
}
string Student::pass()
{
return (grade > 60 ? "yes" : "no");
}
void Student::printStatus()
{
cout << "Name : " << name << endl;
cout << "Degree : " << grade << endl;
cout << "Success : " << pass() << endl;
cout << endl;
}
عند تشغيل هذا الكود سنحصل على النتيجة.
Name: Saja
Degree: 100
Success: yes
Name: Mohammad
Degree: 30
Success: no
تعلمنا على كيفية فصل بعض الدوال من تصميم الكلاس إلى خارج الكلاس بحيث نقوم بإكمال تعريف الدوال خارج الكلاس.
و في الحقيقة هذه الطريقة الأمثل لتصميم الكلاس و يسمى الجزء الأول من البرنامج برأس الكلاس أو class header.
فقط نقوم بتعريف المُتغيرات و الدوال الموجودة و لا نقوم بكتابة أي كود.
بداخل الدالة فقط نقوم بتعريف مُتغيرات و تعريف دوال و لا نقوم بكتابة كود أو تعليمات برمجية سيتم تشغيلها فقط تعريف.
فصل الكلاس عن ملف main في C++
فصل ملف class عن ملف main, نُريد فصل الكلاس الذي انشأناه في الدرس السابق و جميع ما يخص الكلاس في ملف آخر و نريد في الملف الرئيسي فقط الدالة main لكي يكون الكود أكثر وضوحاً و اكثر تقسيماً.
خطوات فصل الكلاس عن ملف main
منذ بداية الدورة عملنا على برنامج CodeBlocks نقوم بترك المشروع الذي انشأناه في الدرس السابق.
و نقوم بالضغط على كلمة File في أقصى يسار البرنامج من الشريط العلوي, ثم نختار New أي ملف جديد لأننا نريد فقط إضافة ملف إلى هذا المشروع ثم نختار Class.
ثم نقوم بكتابة إسم الكلاس كما هو في ملف Main, نحن لدينا الكلاس إسمه Student نقوم بكتابة إسمه كما موضح بالشكل.
بعد ذلك نضغط على Create, سوف يُنتشئ لنا ملفين جديدات و هما Student.h و Student.cpp كما موضخ بالشكل.
و بداخل الملفين الذي قمنا بإنشاءهم ستكون اكوادهم التلقائية هي
- ملف Student.h
- ملف Student.cpp
في الدرس السابق قُلنا أن الجزء الأول من البرنامج يُسمى برأس الكلاس أو class header و هو ما سيتم وضعه في ملف Student.h.
سوف نقوم بقصه من كود الدرس السابق و لصقه في Student.h كما يلي.
#include <iostream>
using namespace std;
#ifndef STUDENT_H
#define STUDENT_H
class Student{
private:
string name;
double grade;
public:
Student(string n, double g);
void setName(string n);
void setGrade(int g);
string pass();
void printStatus();
};
#endif // STUDENT_H
و في Student.cpp الذي يُسمى ملف العمل نقوم بحذف جميع أكواده الموجودة التلقائية.
نُلاحظ في بدايته يكون كلمة Student مكتوبة بين علامتي تنصيص المزدوجه "" و ليس علامات اكبر من و اصغر من <>.
و الفرق بينهم هي أن علامة التنصيص المزدوجة تعني أن هذا الملف موجود في المشروع.
أما include iomanip هي خاصة بالمكتبات التي يجب جلبها من الخارج و ليست ملفات مكتوبة في هذا الملف.
و في ملف Student.cpp نقوم بقص ما كان يوجد أسفل main في مثال الدرس السابق و لصقه بها كما يلي.
#include "Student.h"
Student::Student(string n, double g)
{
setName(n);
setGrade(g);
}
void Student::setName(string n)
{
name = n;
}
void Student::setGrade(int g)
{
grade = g;
}
string Student::pass()
{
return (grade > 60 ? "yes" : "no");
}
void Student::printStatus()
{
cout << "Name : " << name << endl;
cout << "Degree : " << grade << endl;
cout << "Success : " << pass() << endl;
cout << endl;
}
و ملف main سوف يتم به فقط كتابة القيم أي علامات الطلبة.
و لكي يتم تعريف الكلاس نكتب include "Student.h" في بدايته كما بالكود الآتي..
#include <iostream>
#include "Student.h"
using namespace std;
int main()
{
Student saja("Saja", 100);
saja.printStatus();
Student data("Mohammad", 30);
data.printStatus();
return 0;
}
وعند تشغيل البرنامج السابق سنحصل على النتيجة الآتية
Name: Saja
Degree: 100
Success: yes
Name: Mohammad
Degree: 30
Success: no
تطبيق عملي 1
قم بإنشاء كلاس لمستطيل و خصائص المستطيل هي الطول و العرض من نوع float.
و يجب إنشاء دالتان الأولى تقوم بإرجاع مساحة المستطيل و مساحة المستطيل هي الطول ضرب العرض.
و الدالة الثانية تقوم بإرجاع محيط المستطيل و محيط المستطيل يساوي إثنان ضرب الطول + العرض.
و يجب علينا إنشاء دوال set و get و جميع المتغيرات تكون من نوع private.
و تقوم دالة set بالتأكد ما إن كانت القيمة المُدخَلة أقل أو تساوي 20 و أكبر من 0 لكلا الدالتين.
سوف نستخدم الطريقة التي إستخدمناها في الدرس السابق و هي فصل الكلاس عن main ليسهِّل علينا قراءة البرنامج.
الكلاس لدينا سيكون إسمه Rectangle.
- ملف main
#include <iostream>
#include "Rectangle.h"
using namespace std;
int main()
{
Rectangle rect = Rectangle(3, 2);
cout << "المستطيل طوله" << rect.getHeight() << endl;
cout << "عرضه" << rect.getWidth() << endl;
cout << "مساحته" << rect.area() << endl;
cout << "محيطه" << rect.perimeter() << endl;
return 0;
}
في هذا الملف فقط قمنا بإنشاء كائن rect مشتق من الكلاس Rectangle ووضعنا له القيم الطول 3 و عرضه 2.
ثم وضعنا أوامر الطباعة في البداية يقوم بطباعة طول المستطيل عن طريق إستدعاء الدالة getHeight عن طريق الكائن rect.
و يليه طباعة عرض المستطيل عن طريق إستدعاء getWidth.
و ثم قمنا بالطلب منه بطباعة مساحة هذا المستطيل عن طريق area و كما نعرف بأن مساحة المستطيل هي الطول ضرب العرض.
ثم طلبنا طباعة محيط هذا المستطيل عن طريق perimeter و محيطه هو حاصل جمع الطول و العرض مضروب في إثنان 2.
- ملف Rectangle.h
#ifndef RECTANGLE_H
#define RECTANGLE_H
class Rectangle{
private:
int height, width;
public:
Rectangle(int, int);
/Function
int area();
int perimeter();
/Setters
void setHeight(int);
void setWidth(int);
/Getters
int getHeight();
int getWidth();
};
#endif
لقد انشأنا كلاس بإسم Rectangle و به مُتغيران من نوع int و هم للإرتفاع height و العرض width.
ثم انشأنا الكونستركتور من نوع public و به وضعنا مُتغيرات الدوال و هي area للمساحة و perimeter للمحيط.
و دوال الـ Setters للإرتفاع setHeight و للعرض setWidth و نوعهم عددية int.
و دوال Getters هم للإرتفاع getHeight و للعرض setWidth ثم اغلقنا الكلاس.
- ملف Rectangle.cpp
#include "Rectangle.h"
/Function
Rectangle::Rectangle(int h, int w)
{
setHeight(h);
setWidth(w);
}
int Rectangle::area()
{
return height * width;
}
int Rectangle::perimeter()
{
return 2*(height + width);
}
/Setters
void Rectangle::setHeight(int h)
{
height = h;
}
void Rectangle::setWidth(int w)
{
width = w;
}
/Getters
int Rectangle::getHeight()
{
return height;
}
int Rectangle::getWidth()
{
return width;
}
هُنا قمنا بوضع الكونستركتور في البداية ووضعنا الدوال التي تنتمي للكلاس و قمنا بالوصول إليها عبر إضافة إسم الكلاس و بعده نقطتين::.
و قُمنا بتمرير setHeight عبر الحرف h و setWidth عبر الحرف w.
و أتينا إلى مُتغير المساحة ووضعنا له أن يقوم بإرجاع لنا الطول ضرب العرض.
و ثم أتينا لمتغير المحيط perimeter و طلبنا منه أن يقوم بإرجاع لنا ناتج جمع الطول و العرض مضروب بالرقم إثنان.
ثم عرَّفنا دوال Setters و Getters بأن تقوم setHeight بإرجاع h و setWidth تقوم بإرجاع w.
و أن getHeight تقوم بإرجاع height و getWidth تقوم بإرجاع width.
و عند تشغيل الكود سوف نحصل على النتيجة الآتية
The rectangle is its length: 3
susceptible: 2
area: 6
surroundings: 10
نلاحظ من النتيجة السابقة أنه أعطانا المستطيل طوله 3 و عرضه 2 و مساحته 6 أي تعني الطول ضرب العرض و محيطه 10 و هو العرض زائد الطول ضرب 2.
تطبيق عملي 2
قُم بإنشاء كلاس User بحيث يتم السماح للمستخدم بإنشاء مستخدم جديد من خلال إدخال إسم المستخدم و كلمة السر و يقوم بتسجيل هذه البيانات في مصفوفة.
#include <iostream>
using namespace std;
class User
{
private:
string username, password;
public:
void setUsername(string u)
{
username = u;
}
void setPassword(string p)
{
password = p;
}
string getUsername()
{
return username;
}
string getPassword()
{
return password;
}
};
int size = 0; /عدد المستخدمين
User users[100]; /مصفوفة بها 100 عنصر
int main()
{
string username, password;
while(true)
{
cout << "اسم المستخدم" << " ";
cin >> username;
cout << "كلمة المرور" << " ";
cin >> password;
User newUser;
newUser.setUsername(username);
newUser.setPassword(password);
users[size++] = newUser;
for(int i=0; i<size; i++)
{
cout << i << ". " << users[i].getUsername() << endl;
}
}
return 0;
}
انشانا كلاس بإسم User و به مُتغيران من نوع نصي و هُم لليوزرنيم username و الباسورد password.
ثم قُمنا بإنشاء بعض الدوال العامة بـ Setters و هي setUsername تُمرر متغير نصي u و setPassword تُمرر متغير نصي p.
و دوال Getters بأن getUsername تقوم بإرجاع اليوزرنيم و setPassword تقوم بإرجاع الباسورد.
ثم كتبنا متغير إسمه size أي عدد المستخدمين يبدأ العد من 0.
و وضعنا بأن حجم هذه المصفوفة تتسع لـ 100 يوزر.
ثم دخلنا للدالة main و أنشأنا حلقة تكرارية for بداخل حلقة تكرارية while من أجل الطلب من المستخدم كل مرة بأن يضيف بيانات جديدة و يتم تسجيلها في المصفوفة.
و عند التشغيل لهذا البرنامج و تعبئته ببعض البيانات سيكون كما يلي.