القائمة الرئيسية

الصفحات

البرمجة الكائنية والكلاسات في السي بلاس بلاس

C++ مفهوم البرمجة الكائنية (OOP)

البرمجة الكائنية ( Object Oriented Programming ) و التي تختصر بكلمة OOP عبارة عن أسلوب نتبعه في كتابة الكود لجعل كتابة الكود أكثر سهولة.
إذاً البرمجة الكائنية هي مجرد أسلوب في العمل لا أكثر و هي ليست خاصة بلغة C++ حيث أنها تطبق في باقي لغات البرمجة.

فكرة البرمجة الكائنية بشكل عام هي تجهيز الشكل الذي سيتم فيه حفظ المعلومات مما يجعل الوصول إليها و التعديل عليها سهل للغاية.

كمثال بسيط, إذا كنت تنوي بناء برنامج لحفظ معلومات المستخدمين, ستقوم بتجهيز الشكل العام للمعلومات التي تنوي حفظها لكل مستخدم.
بعدها, أي مستخدم جديد تنوي إنشاؤه تجعله نسخة من الشكل العام لأي مستخدم و تجعله يدخل القيم الخاصة به كما في الصورة التالية.


الآن, عليك معرفة أن النوع الجديد أو الشكل الذي تقوم بتجهيزه بهدف إنشاء نسخ منه لاحقاً يقال له النسخة الخام ( Blue Print ).
كلمة النسخة الخام يقصد بها النسخة الأصلية التي يتم تجهيزها بهدف إنشاء نسخ منها.

في C++ لديك خيارين لإنشاء نوع جديد و هما:

  • أن تنشئه بواسطة الكلمة struct

  • أن تنشئه بواسطة الكلمة class

ملاحظة: ستعرف الفرق بين هاتين الكلمتين لاحقاً في الدورة.


ما هو الكائن؟

بشكل عام, الكائن ( Object ) عبارة عن نسخة من نوع محدد تم تعريفه بالأساس بواسطة الكلمة struct أو الكلمة class.


أمثلة واقعية عن دور الكائنات

من أكثر أنواع المشاريع التي قد تجد أنك تتعامل فيها مع عدد هائل من الكائنات هو برمجة الألعاب.

كمثال بسيط, في أي لعبة تلعبها تجد أنه يوجد شرير و لكن هذا الشرير قد يظهر لك نفسه مئات المرات في اللعبة.
أيضاً في بعض الألعاب تجد مطر يتساقط, و للدقة أكثر فإنك تجد نفس قطرة المطر تنزل في أماكن مختلفة من الشاشة.

إذاً في الألعاب, يتم تجهيز الشرير في الأصل مرة واحدة و كلما أرادوا أن يظهروا لك نفس الشرير, يقوموا بإنشاء نسخة منه فقط.
و حتى بالنسبة للمطر فإنه أيضاً يمكن تجهيز قطرة مطر واحدة و كلما أرادوا أن يظهروا لك مطر, يقوموا بإنشاء عشرات النسخ منها و إظهارها في أماكن مختلفة.


C++ النوع struct

الكلمة struct في C++

في الدروس السابقة, كنا نتعامل دائماً مع أنواع بيانات بسيطة فمثلاً كنا نقوم بتعريف متغير نوعه int و هذا المتغير كنا نضع فيه قيمة واحدة فقط.
الأنواع البسيطة مفيدة جداً و سنتعامل معها دائماً و لكن في حالات معينة لا بد لنا من تعريف أنواع جديدة.

كمثال بسيط, إذا كنا ننوي إرسال معلومات مجموعة من المنتجات و كل منتج يملك المعلومات التالية: إسم المنتج, تاريخ إنتاجه, سعره و مكوناته.
هنا سيكون خيار ممتاز أن ننشئ نوع جديد يمثل المنتج, أي نوع فيه المعلومات الأساسية التي لا بد أن يمتلكها أي منتج.
و عندها أي منتج جديد نريد تعريفه, نجعله نسخة منه.

الكلمة struct تستخدم لتعريف نوع جديد و هذا النوع يمكنه أن يحتوي على مجموعة من القيم من أي نوع كانت بشكل مرتب و سهل التعامل معها.
على الأغلب, ستجد النوع الجديد الذي يتم تعريفه بواسطة الكلمة struct يستخدم لهذا الغرض فقط.
و لكن عليك معرفة أنه يمكنه أن يحتوي على أي شيء آخر, مثل دوال خاصة به و حتى struct آخر و سترى ذلك لاحقاً في الأمثلة.


مصطلحات تقنية

أي نوع جديد تعرّفه بواسطة الكلمة struct يقال له Structure.
أي نسخة تنشئها من النوع الجديد الذي قمت بتعريفه يقال لها كائن ( Object ) منه.

تعريف struct جديد في C++

إذا كنت ستقوم بتعريف النوع الجديد بواسطة الكلمة struct فيجب أن تتبع الأسلوب التالي.

struct struct_name {
    member_definition;
    member_definition;
    member_definition;
    ..
} object_names;
  • struct_name:   مكانها نضع الإسم الذي سنعطيه للنوع الجديد.

  • member_definition:   هنا يمكنك تمرير إسم و نوع أي شيء تنوي جعل النوع الجديد يملكه.

  • object_names:   إذا أردت إنشاء كائن (نسخة) من النوع الجديد مباشرةً عند تعريفه, فأي إسم تضعه هنا سيتم إعتباره كائن منه.

الآن عليك معرفة أنه يمكنك تعريف struct في أي مكان تريده, فمثلاً يمكنك تعريفه في ملف خاص, خارج الدالة main() و حتى بداخلها إن أردت.


في المثال التالي, قمنا بتعريف نوع جديد إسمه Book يمثل المعلومات التي يمكن أن يتضمنها أي كتاب كعنوانه, إسم المؤلف, سعره و عدد صفحاته.

مثال

	  struct Book {
	  string title;
	  string author;
	  double price;
	  int numberOfPages;
	  };
	

إنشاء كائن من struct في C++

هناك عدة طرق يمكن اتباعها لإنشاء كائنات من struct و يمكنك اتباع أي طريقة تريد منها.


في المثال التالي قمنا بإنشاء struct إسمه Book و من ثم إنشاء كائن منه.

المثال الأول

	  // يحتوي على 4 متغيرات Book إسمه struct هنا قمنا بتعريف
	  struct Book {
	  string title;
	  string author;
	  double price;
	  int numberOfPages;
	  };

	  // book إسمه Book هنا قمنا بإنشاء كائن من
	  struct Book book;
	

في المثال التالي قمنا بإنشاء struct إسمه Book و إنشاء كائن منه بشكل مباشر.
إذاً, هذا المثال هو نفس المثال الأول بالضبط و لكن الكود مكتوب فيه بشكل مختصر فقط.

المثال الثاني

	  // book يحتوي على 4 متغيرات. و من ثم قمنا بإنشاء كائن منه إسمه Book إسمه struct هنا قمنا بتعريف
	  struct Book {
	  string title;
	  string author;
	  double price;
	  int numberOfPages;
	  } book;
	

في المثال التالي قمنا بإنشاء struct إسمه Book و من ثم إنشاء ثلاث كائنات منه.

المثال الثالث

	  // يحتوي على 4 متغيرات Book إسمه struct هنا قمنا بتعريف
	  struct Book {
	  string title;
	  string author;
	  double price;
	  int numberOfPages;
	  };

	  // book3 و الثالث إسمه book2 الثاني إسمه ,book1 الأول إسمه ,Book هنا بإنشاء ثلاث كائنات من
	  struct Book book1;
	  struct Book book2;
	  struct Book book3;
	

في المثال التالي قمنا بإنشاء struct إسمه Book و من ثم إنشاء ثلاث كائنات منه.
إذاً, هذا المثال هو نفس المثال الثالث بالضبط و لكن الكود مكتوب فيه بشكل مختصر فقط.

المثال الرابع

	  // يحتوي على 4 متغيرات Book إسمه struct هنا قمنا بتعريف
	  struct Book {
	  string title;
	  string author;
	  double price;
	  int numberOfPages;
	  };

	  // book3 و الثالث إسمه book2 الثاني إسمه ,book1 الأول إسمه ,Book هنا بإنشاء ثلاث كائنات من
	  struct Book book1, book2, book3;
	

الوصول للأشياء الموجودة بداخل كائن من struct في C++

للوصول لقيم المتغيرات الموجودة فيه, نستخدم العامل . أي النقطة العادية.


مصطلحات تقنية

العامل . يقال له Member Operator لأنه يسمح لنا بالوصول لأي شيء ( Member ) موجود في الكائن.


في المثال التالي, قمنا بتعريف struct إسمه Book يمثل المعلومات التي يمكن أن يتضمنها أي كتاب كعنوانه, إسم المؤلف, سعره و عدد صفحاته.
بعدها قمنا بإنشاء كائنين منه و من ثم إعطاء كل واحد قيم خاصة به.

مثال

main.cpp
	  #include <iostream>

	  using namespace std;

	  // يحتوي على 4 متغيرات Book إسمه struct هنا قمنا بتعريف
	  struct Book {
	  string title;
	  string author;
	  double price;
	  int numberOfPages;
	  };

	  int main()
	  {
	  // book2 و الثاني إسمه book1 الأول إسمه ,Book هنا قمنا بتعريف كائنين من
	  struct Book book1;
	  struct Book book2;

	  // book1 هنا قمنا بإعطاء قيم لمتغيرات الكائن
	  book1.title = "C++ for beginners";
	  book1.author = "Mhamad Harmush";
	  book1.price = 9.99;
	  book1.numberOfPages = 420;

	  // book2 هنا قمنا بإعطاء قيم لمتغيرات الكائن
	  book2.title = "Network 1";
	  book2.author = "Nadine Masri";
	  book2.price = 22.49;
	  book2.numberOfPages = 310;

	  // book1 هنا قمنا بعرض قيم الكائن
	  cout << "Book 1 ----------- \n";
	  cout << "Title: " << book1.title << "\n";
	  cout << "Author: " << book1.author << "\n";
	  cout << "Price: " << book1.price << "$\n";
	  cout << "Number of pages: " << book1.numberOfPages << "\n\n";

	  // book2 هنا قمنا بعرض قيم الكائن
	  cout << "Book 2 ----------- \n";
	  cout << "Title: " << book2.title << "\n";
	  cout << "Author: " << book2.author << "\n";
	  cout << "Price: " << book2.price << "$\n";
	  cout << "Number of pages: " << book2.numberOfPages;

	  return 0;
	  }
	

سنحصل على النتيجة التالية عند التشغيل.

	  Book 1 -----------
	  Title: C++ for beginners
	  Author: Mhamad Harmush
	  Price: 9.99$
	  Number of pages: 420

	  Book 2 -----------
	  Title: Network 1
	  Author: Nadine Masri
	  Price: 22.49$
	  Number of pages: 310
	

أمثلة شاملة


المثال الأول

هنا وضعنا مثال حول كيفية تعريف دالة تأخذ باراميتر نوعه struct بالإضافة إلى كيفية إستدعاءها.

في المثال التالي, قمنا بتعريف struct إسمه Book يمثل المعلومات التي يمكن أن يتضمنها أي كتاب كعنوانه, إسم المؤلف, سعره و عدد صفحاته.
بعدها قمنا بتعريف دالة إسمها printInfo عند استدعاءها نمرر لها كائن نوعه Book فتقوم بطباعة قيمه بشكل مرتب.

في الأخير قمنا بإنشاء كائن من Book و إعطاؤه قيم, و من ثم تمريره للدالة printInfo() حتى تقوم بطباعة قيمه.

مثال

main.cpp
	  #include <iostream>

	  using namespace std;

	  // يحتوي على 4 متغيرات Book إسمه struct هنا قمنا بتعريف
	  struct Book {
	  string title;
	  string author;
	  double price;
	  int numberOfPages;
	  };

	  // فتقوم بطباعة كل قيم المتغيرات الموجودة فيه Book عند استدعاءها نمرر لها كائن من printInfo هنا قمنا بتعريف دالة إسمها
	  void printInfo(struct Book book)
	  {
	  cout << "Title: " << book.title << "\n";
	  cout << "Author: " << book.author << "\n";
	  cout << "Price: " << book.price << "$\n";
	  cout << "Number of pages: " << book.numberOfPages << "\n";
	  }

	  // main() هنا قمنا بتعريف الدالة
	  int main()
	  {
	  // book إسمه Book هنا قمنا بتعريف كائن من
	  struct Book book;

	  // book هنا قمنا بإعطاء قيم لمتغيرات الكائن
	  book.title = "C++ for beginners";
	  book.author = "Mhamad Harmush";
	  book.price = 9.99;
	  book.numberOfPages = 420;

	  // لها حتى تقوم بطباعة القيم الموجودة فيه book و تمرير الكائن printInfo() هنا قمنا باستدعاء الدالة
	  printInfo(book);

	  return 0;
	  }
	

سنحصل على النتيجة التالية عند التشغيل.

	  Title: C++ for beginners
	  Author: Mhamad Harmush
	  Price: 9.99$
	  Number of pages: 420
	


المثال الثاني

هنا وضعنا مثال حول كيفية تعريف دالة بداخل struct بالإضافة إلى كيفية إستدعاءها منه.

في المثال التالي, قمنا بتعريف struct إسمه Book يمثل المعلومات التي يمكن أن يتضمنها أي كتاب كعنوانه, إسم المؤلف, سعره و عدد صفحاته.
كما أننا قمنا بوضع دالة إسمها printInfo بداخل الـstruct عند استدعاءها من أي كائن ننشئه منه تقوم بطباعة قيمه بشكل مرتب.

في الأخير قمنا بإنشاء كائن من Book و إعطاؤه قيم, و من ثم إستدعاء الدالة printInfo() منه حتى تقوم بطباعة قيمه.

مثال

main.cpp
	  #include <iostream>

	  using namespace std;

	  // يحتوي على 4 متغيرات Book إسمه struct هنا قمنا بتعريف
	  struct Book {
	  string title;
	  string author;
	  double price;
	  int numberOfPages;

	  // تقوم بطباعة كل قيم المتغيرات الموجودة فيه Book عند استدعاء من أي كائن ننشئه من printInfo هنا قمنا بتعريف دالة إسمها
	  void printInfo()
	  {
	  cout << "Title: " << title << "\n";
	  cout << "Author: " << author << "\n";
	  cout << "Price: " << price << "$\n";
	  cout << "Number of pages: " << numberOfPages << "\n";
	  }
	  };

	  // main() هنا قمنا بتعريف الدالة
	  int main()
	  {
	  // book إسمه Book هنا قمنا بتعريف كائن من
	  struct Book book;

	  // book هنا قمنا بإعطاء قيم لمتغيرات الكائن
	  book.title = "C++ for beginners";
	  book.author = "Mhamad Harmush";
	  book.price = 9.99;
	  book.numberOfPages = 420;

	  // حتى تقوم بطباعة القيم الموجودة فيه book من الكائن printInfo() هنا قمنا باستدعاء الدالة
	  book.printInfo();

	  return 0;
	  }
	

سنحصل على النتيجة التالية عند التشغيل.

	  Title: C++ for beginners
	  Author: Mhamad Harmush
	  Price: 9.99$
	  Number of pages: 420
	


المثال الثالث

هنا وضعنا مثال حول كيفية تعريف دالة تأخذ باراميتر نوعه مؤشر لـ struct بالإضافة إلى كيفية إستدعاءها.

للوصول للأشياء الموجودة في مؤشر لـ struct نستخدم العامل -> و ليس العامل . المعتاد.


في المثال التالي, قمنا بتعريف struct إسمه Book يمثل المعلومات التي يمكن أن يتضمنها أي كتاب كعنوانه, إسم المؤلف, سعره و عدد صفحاته.
بعدها قمنا بتعريف دالة إسمها printInfo عند استدعاءها نمرر لها عنوان كائن من Book موجود في الذاكرة فتقوم بطباعة قيمه بشكل مرتب.

في الأخير قمنا بإنشاء كائن من Book و إعطاؤه قيم, و من ثم تمرير عنوانه في الذاكرة للدالة printInfo() حتى تقوم بطباعة قيمه.

مثال

main.cpp
	  #include <iostream>

	  using namespace std;

	  // يحتوي على 4 متغيرات Book إسمه struct هنا قمنا بتعريف
	  struct Book {
	  string title;
	  string author;
	  double price;
	  int numberOfPages;
	  };

	  // فتقوم بطباعة كل قيم المتغيرات الموجودة فيه Book عند استدعاءها نمرر لها عنوان كائن من printInfo هنا قمنا بتعريف دالة إسمها
	  void printInfo(struct Book* book)
	  {
	  cout << "Title: " << book->title << "\n";
	  cout << "Author: " << book->author << "\n";
	  cout << "Price: " << book->price << "$\n";
	  cout << "Number of pages: " << book->numberOfPages << "\n";
	  }

	  // main() هنا قمنا بتعريف الدالة
	  int main()
	  {
	  // book إسمه Book هنا قمنا بتعريف كائن من
	  struct Book book;

	  // book هنا قمنا بإعطاء قيم لمتغيرات الكائن
	  book.title = "C++ for beginners";
	  book.author = "Mhamad Harmush";
	  book.price = 9.99;
	  book.numberOfPages = 420;

	  // لها حتى تقوم بطباعة القيم الموجودة فيه book و تمرير عنوان الكائن printInfo() هنا قمنا باستدعاء الدالة
	  printInfo(&book);

	  return 0;
	  }
	

سنحصل على النتيجة التالية عند التشغيل.

	  Title: C++ for beginners
	  Author: Mhamad Harmush
	  Price: 9.99$
	  Number of pages: 420
	


المثال الرابع

هنا وضعنا مثال حول كيفية وضع إسم مختصر للنوع struct بالإعتماد على الكلمة typedef.

للوصول للأشياء الموجودة في مؤشر لـ struct نستخدم العامل -> و ليس العامل . المعتاد.


في المثال التالي, قمنا بتعريف struct إسمه Book يمثل المعلومات التي يمكن أن يتضمنها أي كتاب كعنوانه, إسم المؤلف, سعره و عدد صفحاته.
بعدها قمنا بتعريف دالة إسمها printInfo عند استدعاءها نمرر لها عنوان كائن من Book موجود في الذاكرة فتقوم بطباعة قيمه بشكل مرتب.

في الأخير قمنا بإنشاء كائن من Book و إعطاؤه قيم, و من ثم تمرير عنوانه في الذاكرة للدالة printInfo() حتى تقوم بطباعة قيمه.

مثال

main.cpp
	  #include <iostream>

	  using namespace std;

	  // يحتوي على 4 متغيرات Book إسمه struct هنا قمنا بتعريف
	  struct Book {
	  string title;
	  string author;
	  double price;
	  int numberOfPages;
	  };

	  // فتقوم بطباعة كل قيم المتغيرات الموجودة فيه Book عند استدعاءها نمرر لها عنوان كائن من printInfo هنا قمنا بتعريف دالة إسمها
	  void printInfo(struct Book* book)
	  {
	  cout << "Title: " << book->title << "\n";
	  cout << "Author: " << book->author << "\n";
	  cout << "Price: " << book->price << "$\n";
	  cout << "Number of pages: " << book->numberOfPages << "\n";
	  }

	  // main() هنا قمنا بتعريف الدالة
	  int main()
	  {
	  // book إسمه Book هنا قمنا بتعريف كائن من
	  struct Book book;

	  // book هنا قمنا بإعطاء قيم لمتغيرات الكائن
	  book.title = "C++ for beginners";
	  book.author = "Mhamad Harmush";
	  book.price = 9.99;
	  book.numberOfPages = 420;

	  // لها حتى تقوم بطباعة القيم الموجودة فيه book و تمرير عنوان الكائن printInfo() هنا قمنا باستدعاء الدالة
	  printInfo(&book);

	  return 0;
	  }
	

سنحصل على النتيجة التالية عند التشغيل.

	  Title: C++ for beginners
	  Author: Mhamad Harmush
	  Price: 9.99$
	  Number of pages: 420
	


المثال الخامس

في الأمثلة السابقة, لاحظنا أنه كلما أردنا إنشاء كائن من Book كان لا بد لنا من أن نكتب struct Book.
إذا أردت إختصار هاتين الكلمتين بكلمة واحدة فقط, يمكنك وضع إسم مختصر للنوع Book لحظة تعريفه و عندها يمكنك استخدامه كلما أردت إنشاء كائن منه.


في المثال التالي قمنا بإنشاء struct و أعطيناه Book كإسم مختصر بالإعتماد على الكلمة using.
بعدها قمنا بإنشاء ثلاث كائنات منه باستخدام الإسم المختصر الذي وضعناه له.

مثال

	  // كإسم مختصر و وضعنا فيه 4 متغيرات Book أعطيناه الكلمة struct هنا قمنا بتعريف
	  using Book = struct {
	  string title;
	  string author;
	  double price;
	  int numberOfPages;
	  };

	  // book3 و الثالث إسمه book2 الثاني إسمه ,book1 الأول إسمه ,Book هنا بإنشاء ثلاث كائنات من
	  Book book1, book2, book3;
	

C++ النوع class

مفهوم الكلاس في C++

الكلاس عبارة عن نوع جديد يتم تعريفه بواسطة الكلمة class و هذا النوع يمكنه أن يحتوي على دوال, متغيرات, مصفوفات إلخ..

النوع الذي تقوم بتعريفه بوسطة الكلمة class يشبه بشكل كبير النوع الذي تقوم بتعريفه بواسطة الكلمة struct التي تعرفنا عليها في الدرس السابق.
لهذا السبب سنبدأ بذكر الفرق بينهما حتى لا ترتبك من شدة التشابه الذي ستلاحظه بينهما.

الفرق الأساسي بين النوع الذي يتم تعريفه بواسطة الكلمة class و النوع الذي يتم تعريفه بواسطة الكلمة struct هو أن هذا الأخير يمكن الوصول لأي شيء موجود فيه بشكل مباشر, بينما في النوع class أنت تحدد ما إن كان يمكن الوصول للأشياء التي تضعها فيه بشكل مباشر أم لا.

إمكانية تحديد الطريقة التي يمكن فيها الوصول للأشياء الموجودة في الكلاس تمكننا من تطبيق كل مبادئ البرمجة الكائنية ( OOP ) المتعارف عليها.
لهذا سنركز بشكل كبير في الدروس القادمة على التعامل مع الكلاس بشكل خاص.

تعريف كلاس في C++

لتعريف كلاس جديد نكتب الكلمة class ثم نعطيه إسم, ثم نفتح أقواس تحدد بدايته و نهايته.


المثال التالي يوضح طريقة تعريف كلاس فارغ إسمه Book.

مثال

		class Book {
		// هنا يمكنك تعريف كل ما سيحتويه الكلاس
		};
	  

معلومة تقنية

في المشاريع الحقيقية, أي كلاس جديد نريد تعريفه نقوم في العادة بإنشاء ملف نوعه cpp خاص له و نضع الكود الخاص به بداخله.
بعدها في أي مكان نريد أن نتعامل معه نقوم بتضمين الملف الذي يحتويه.
الآن, بهدف جعل الشرح بسيط و سهل الفهم سنكتب الكود كله بداخل نفس الملف و في آخر الدرس سنعلمك كيف تنشئ الكلاس في ملف خاص أيضاً.

مفهوم الخصائص في C++

الخصائص ( Attributes ) هي الأشياء (المتغيرات, المصفوفات و الكائنات) التي يتم تعريفها بداخل الكلاس و التي سيملك نسخة خاصة منها أي كائن ننشئه منه.

أي شيء تنوي تعريفه في الكلاس لا بدل لك من تحديد كيفية الوصول إليه كما قلنا سابقاً.
لتحدد كيفية الوصول للأشياء التي تضعها في الكلاس يمكنك استخدام الكلمات المخصصة لذلك و التي يقال لها Access Specifiers, أي الكلمات التالية.

الكلمة إستخدامها
public تستخدم لتحديد أن الأشياء الموضوعة في الكلاس يمكن الوصول لها من أي مكان.
private تستخدم لتحديد أن الأشياء الموضوعة في الكلاس لا يمكن الوصول لها من خارجه.
protected تستخدم لتحديد أن الأشياء الموضوعة في الكلاس يمكن الوصول لها عند وراثتها.
ملاحظة: سنتعلم الوراثة في دروس لاحقة.

ملاحظة

ستعرف متى يجب أن نستخدم الكلمتين private و protected بشكل عملي في دروس لاحقة و لكن الآن يكفي أن تعرف أنها من الخيارات المتاحة في C++ و معرفة كيف يمكن وضعها بداخل الكلاس.


المثال التالي يوضح طريقة وضع الكلمات public و private و protected في الكلاس.

المثال الأول

		class Book {

		public:
		// public هنا أي شيء نقوم بتعريفه يعتبر أنه

		private:
		// private هنا أي شيء نقوم بتعريفه يعتبر أنه

		protected:
		// protected هنا أي شيء نقوم بتعريفه يعتبر أنه

		};
	  

في المثال التالي قمنا بتعريف كلاس إسمه Book و بداخله قمنا بتعريف 4 متغيرات نوعهم public.
ملاحظة: لم نضع الكلمتين private و protected في الكلاس لأننا لم نحتاجهم.

المثال الثاني

		class Book {

		public:
		string title;
		string author;
		double price;
		int numberOfPages;

		};
	  

إنشاء كائن من كلاس و إعطاؤه قيم في C++

إنشاء كائن من كلاس أمر بغاية السهولة, فكل ما عليك فعله هو اعتماد نفس الطريقة التي تعتمدها لإنشاء متغير عادي.
و بالنسبة للوصول للأشياء التي يملكها الكائن, فيمكنك الوصول لأي شيء موجود فيه طالما أن نوعه public من خلال كتابة إسم الكائن ثم وضع نقطة ثم وضع إسم الشيء الذي تريد الوصول إليه.


في المثال التالي قمنا بتعريف كلاس إسمه Book و بداخله قمنا بتعريف 4 متغيرات نوعهم public.
بعدها قمنا بإنشاء كائنين منه و إعطاء قيم للمتغيرات الموجودة فيهما.

مثال

main.cpp
		#include <iostream>

		using namespace std;

		// يحتوي على 4 متغيرات Book هنا قمنا بتعريف كلاس إسمه
		class Book {

		public:
		string title;
		string author;
		double price;
		int numberOfPages;

		};

		int main()
		{
		// book2 و الثاني إسمه book1 الأول إسمه ,Book هنا قمنا بتعريف كائنين من
		Book book1;
		Book book2;

		// book1 هنا قمنا بإعطاء قيم لمتغيرات الكائن
		book1.title = "C++ for beginners";
		book1.author = "Mhamad Harmush";
		book1.price = 9.99;
		book1.numberOfPages = 420;

		// book2 هنا قمنا بإعطاء قيم لمتغيرات الكائن
		book2.title = "Network 1";
		book2.author = "Nadine Masri";
		book2.price = 22.49;
		book2.numberOfPages = 310;

		// book1 هنا قمنا بعرض قيم الكائن
		cout << "Book 1 ----------- \n";
		cout << "Title: " << book1.title << "\n";
		cout << "Author: " << book1.author << "\n";
		cout << "Price: " << book1.price << "$\n";
		cout << "Number of pages: " << book1.numberOfPages << "\n\n";

		// book2 هنا قمنا بعرض قيم الكائن
		cout << "Book 2 ----------- \n";
		cout << "Title: " << book2.title << "\n";
		cout << "Author: " << book2.author << "\n";
		cout << "Price: " << book2.price << "$\n";
		cout << "Number of pages: " << book2.numberOfPages;

		return 0;
		}
	  

سنحصل على النتيجة التالية عند التشغيل.

		Book 1 -----------
		Title: C++ for beginners
		Author: Mhamad Harmush
		Price: 9.99$
		Number of pages: 420

		Book 2 -----------
		Title: Network 1
		Author: Nadine Masri
		Price: 22.49$
		Number of pages: 310
	  

مفاهيم مهمة حول الكلاسات في C++


المفهوم الأول

هنا وضعنا مثالين حول كيفية تعريف دالة بداخل كلاس ( Member Function ) بالإضافة إلى كيفية إستدعاءها منه.

من المهم جداً معرفة أنه يمكنك تعريف دوال الكلاس بطريقتين:

  • تعريف الدالة كما هي بداخل الكلاس.

  • تعريف شكل الدالة ( Function Header أو Prototype ) فقط بداخل الكلاس و تعريف محتوى الدالة ( Function Body ) خارج تعريف الكلاس.


في المثال التالي, قمنا بتعريف كلاس إسمه Book يمثل المعلومات التي يمكن أن يتضمنها أي كتاب كعنوانه, إسم المؤلف, سعره و عدد صفحاته.
كما أننا قمنا بوضع دالة إسمها printInfo بداخل الكلاس عند استدعاءها من أي كائن ننشئه منه فتقوم بطباعة قيمه بشكل مرتب.

في الأخير قمنا بإنشاء كائن من Book و إعطاؤه قيم, و من ثم إستدعاء الدالة printInfo() منه حتى تقوم بطباعة قيمه.

المثال الأول

main.cpp
		#include <iostream>

		using namespace std;

		// يحتوي على 4 متغيرات Book هنا قمنا بتعريف كلاس إسمه
		class Book {

		public:
		string title;
		string author;
		double price;
		int numberOfPages;

		// تقوم بطباعة كل قيم المتغيرات الموجودة فيه Book عند استدعاءها من أي كائن ننشئه من printInfo هنا قمنا بتعريف دالة إسمها
		void printInfo()
		{
		cout << "Title: " << title << "\n";
		cout << "Author: " << author << "\n";
		cout << "Price: " << price << "$\n";
		cout << "Number of pages: " << numberOfPages << "\n";
		}

		};

		// main() هنا قمنا بتعريف الدالة
		int main()
		{
		// book إسمه Book هنا قمنا بتعريف كائن من
		Book book;

		// book هنا قمنا بإعطاء قيم لمتغيرات الكائن
		book.title = "C++ for beginners";
		book.author = "Mhamad Harmush";
		book.price = 9.99;
		book.numberOfPages = 420;

		// حتى تقوم بطباعة القيم الموجودة فيه book من الكائن printInfo() هنا قمنا باستدعاء الدالة
		book.printInfo();

		return 0;
		}
	  

سنحصل على النتيجة التالية عند التشغيل.

		Title: C++ for beginners
		Author: Mhamad Harmush
		Price: 9.99$
		Number of pages: 420
	  

هنا قمنا بإعادة المثال السابق مع فارق واحد و هو أننا قمنا بتعريف شكل الدالة ( Prototype ) فقط بداخل الكلاس و محتواها خارجه.

المثال الثاني

main.cpp
		#include <iostream>

		using namespace std;

		// يحتوي على 4 متغيرات Book هنا قمنا بتعريف كلاس إسمه
		class Book {

		public:
		string title;
		string author;
		double price;
		int numberOfPages;

		// printInfo() هنا قمنا بتعريف شكل الدالة
		void printInfo();

		};

		// و جعلناها تقوم بطباعة قيم متغيرات الكائن الذي يستدعيها Book الموجودة في الكلاس printInfo هنا قمنا بتعريف محتوى الدالة
		void Book::printInfo()
		{
		cout << "Title: " << title << "\n";
		cout << "Author: " << author << "\n";
		cout << "Price: " << price << "$\n";
		cout << "Number of pages: " << numberOfPages << "\n";
		}

		// main() هنا قمنا بتعريف الدالة
		int main()
		{
		// book إسمه Book هنا قمنا بتعريف كائن من
		Book book;

		// book هنا قمنا بإعطاء قيم لمتغيرات الكائن
		book.title = "C++ for beginners";
		book.author = "Mhamad Harmush";
		book.price = 9.99;
		book.numberOfPages = 420;

		// حتى تقوم بطباعة القيم الموجودة فيه book من الكائن printInfo() هنا قمنا باستدعاء الدالة
		book.printInfo();

		return 0;
		}
	  

سنحصل على النتيجة التالية عند التشغيل.

		Title: C++ for beginners
		Author: Mhamad Harmush
		Price: 9.99$
		Number of pages: 420
	  


المفهوم الثاني

هنا وضعنا مثال حول كيفية تعريف دالة تأخذ باراميتر عبارة كائن ( Object Parameter ) من كلاس بالإضافة إلى كيفية إستدعاءها.

في المثال التالي, قمنا بتعريف كلاس إسمه Book يمثل المعلومات التي يمكن أن يتضمنها أي كتاب كعنوانه, إسم المؤلف, سعره و عدد صفحاته.
بعدها قمنا بتعريف دالة إسمها printInfo عند استدعاءها نمرر لها كائن نوعه Book فتقوم بطباعة قيمه بشكل مرتب.

في الأخير قمنا بإنشاء كائن من Book و إعطاؤه قيم, و من ثم تمريره للدالة printInfo() حتى تقوم بطباعة قيمه.

مثال

main.cpp
		#include <iostream>

		using namespace std;

		// يحتوي على 4 متغيرات Book هنا قمنا بتعريف كلاس إسمه
		class Book {

		public:
		string title;
		string author;
		double price;
		int numberOfPages;

		};

		// فتقوم بطباعة كل قيم المتغيرات الموجودة فيه Book عند استدعاءها نمرر لها كائن من printInfo هنا قمنا بتعريف دالة إسمها
		void printInfo(Book book)
		{
		cout << "Title: " << book.title << "\n";
		cout << "Author: " << book.author << "\n";
		cout << "Price: " << book.price << "$\n";
		cout << "Number of pages: " << book.numberOfPages << "\n";
		}

		// main() هنا قمنا بتعريف الدالة
		int main()
		{
		// book إسمه Book هنا قمنا بتعريف كائن من
		Book book;

		// book هنا قمنا بإعطاء قيم لمتغيرات الكائن
		book.title = "C++ for beginners";
		book.author = "Mhamad Harmush";
		book.price = 9.99;
		book.numberOfPages = 420;

		// لها حتى تقوم بطباعة القيم الموجودة فيه book و تمرير الكائن printInfo() هنا قمنا باستدعاء الدالة
		printInfo(book);

		return 0;
		}
	  

سنحصل على النتيجة التالية عند التشغيل.

		Title: C++ for beginners
		Author: Mhamad Harmush
		Price: 9.99$
		Number of pages: 420
	  


المفهوم الثالث

هنا وضعنا مثال حول كيفية استخدام العامل this-> للتفرقة بين باراميترات الدوال و الخصائص الموجودة في الكلاس.
هذا العامل يجعلك قادر على استخدام نفس الأسماء للبارميترات و الخصائص.

العامل this-> يقال له This Pointer, و هم يستخدم للتفرقة بين باراميترات الدوال و الخصائص الموجودة في الكلاس مما يجعلك قادر على وضع نفس الأسماء للبارميترات و الخصائص و تجنب حدوث أي أخطاء منطقية بسبب الأسماء المتشابهة.

الآن, سنضع لك عدة أمثلة حتى تلاحظ الأخطاء المنطقية التي قد تقع فيها بسبب الأسماء المتشابهة و كيف أن العامل this-> يحل لك هذه المشكلة.


في المثال التالي, قمنا بتعريف كلاس إسمه Book يمثل المعلومات التي يمكن أن يتضمنها أي كتاب كعنوانه, إسم المؤلف, سعره و عدد صفحاته.
في الكلاس Book بتعريف دالة إسمها setTitle() عند استدعاءها نمرر لها نص فيتم وضعه كعنوان للكائن الذي قام باستدعائها.

المثال الأول

main.cpp
		#include <iostream>

		using namespace std;

		// يحتوي على 4 متغيرات Book هنا قمنا بتعريف كلاس إسمه
		class Book {

		public:
		// هنا قمنا بتعريف خصائص الكلاس
		string title;
		string author;
		double price;
		int numberOfPages;

		// Book عند استدعاءها من أي كائن ننشئه من setTitle هنا قمنا بتعريف دالة إسمها
		// الذي يملكه الكائن title فتقوم بوضعها كقيمة للمتغير t نمرر لها قيمة مكان الباراميتر 
		void setTitle(string t)
		{
		title = t;
		}
		};


		// main() هنا قمنا بتعريف الدالة
		int main()
		{
		// book إسمه Book هنا قمنا بتعريف كائن من
		Book book;

		// book الخاص بالكائن title و تمرير نص لها حتى تقوم بتخزينه في المتغير book من الكائن setTitle() هنا قمنا باستدعاء الدالة
		book.setTitle("C++ for beginners");

		// للتأكد ما إن كانت قد تغيرت أم لا book الموجود في الكائن title هنا قمنا بطباعة قيمة المتغير
		cout << "Title: " << book.title;

		return 0;
		}
	  

سنحصل على النتيجة التالية عند التشغيل.

		Title: C++ for beginners
	  


في حال قمنا بإعادة المثال السابق مع إجراء تعديل بسيط عليه بحيث نجعل إسم الباراميتر الموضوع في الدالة setTitle() هو نفسه إسم المتغير title الموجود في الكلاس سيظهر لنا مشكلة منطقية عند تشغيل البرنامج كما سنرى في نتيجة التشغيل.

المثال الثاني

main.cpp
		#include <iostream>

		using namespace std;

		// يحتوي على 4 متغيرات Book هنا قمنا بتعريف كلاس إسمه
		class Book {

		public:
		// هنا قمنا بتعريف خصائص الكلاس
		string title;
		string author;
		double price;
		int numberOfPages;

		// title نمرر لها قيمة مكان الباراميتر  Book عند استدعاءها من أي كائن ننشئه من setTitle هنا قمنا بتعريف دالة إسمها
		void setTitle(string title)
		{
		// الموجود في الكلاس title بداخله من جديد. أي لن يتم تمريرها للمتغير title هنا كأننا قلنا, أعد وضع القيمة التي نمررها للباراميتر
		// لأنهما يملكان نفس الإسم title سبب هذه المشكلة أن المترجم لن يعرف أنك تقصد أنك تريد تمرير القيمة التي تمررها للدالة, إلى المتغير
		title = title;
		}
		};


		// main() هنا قمنا بتعريف الدالة
		int main()
		{
		// book إسمه Book هنا قمنا بتعريف كائن من
		Book book;

		// book الخاص بالكائن title و تمرير نص لها حتى تقوم بتخزينه في المتغير book من الكائن setTitle() هنا قمنا باستدعاء الدالة
		book.setTitle("C++ for beginners");

		// للتأكد ما إن كانت قد تغيرت أم لا book الموجود في الكائن title هنا قمنا بطباعة قيمة المتغير
		cout << "Title: " << book.title;

		return 0;
		}
	  

سنحصل على النتيجة التالية عند التشغيل.
لاحظ أن القيمة التي مررناها للدالة setTitle() لم يتم تمريرها للمتغير title الموجود في الكائن book و هذا ما كنا نقصده بخطأ منطقي.

		Title:
	  


لحل المشكلة المنطقة التي شاهدناها في المثال الثاني, أي لجعل المترجم قادر على التفرقة بين البارميترات و المتغيرات الموجودة في الكلاس سنستخدم العامل this-> كلما أردنا الإشارة إلى المتغيرات الموجودة في الكلاس.

المثال الثالث

main.cpp
		#include <iostream>

		using namespace std;

		// يحتوي على 4 متغيرات Book هنا قمنا بتعريف كلاس إسمه
		class Book {

		public:
		// هنا قمنا بتعريف خصائص الكلاس
		string title;
		string author;
		double price;
		int numberOfPages;

		// Book عند استدعاءها من أي كائن ننشئه من setTitle هنا قمنا بتعريف دالة إسمها
		// الذي يملكه الكائن title فتقوم بوضعها كقيمة للمتغير title نمرر لها قيمة مكان الباراميتر 
		void setTitle(string title)
		{
		this->title = title;
		}
		};


		// main() هنا قمنا بتعريف الدالة
		int main()
		{
		// book إسمه Book هنا قمنا بتعريف كائن من
		Book book;

		// book الخاص بالكائن title و تمرير نص لها حتى تقوم بتخزينه في المتغير book من الكائن setTitle() هنا قمنا باستدعاء الدالة
		book.setTitle("C++ for beginners");

		// للتأكد ما إن كانت قد تغيرت أم لا book الموجود في الكائن title هنا قمنا بطباعة قيمة المتغير
		cout << "Title: " << book.title;

		return 0;
		}
	  

سنحصل على النتيجة التالية عند التشغيل.

		Title: C++ for beginners
	  


المفهوم الرابع

الكونستركتور ( Constructor ) عبارة عن دالة مميزة يتم استدعاؤها بشكل تلقائي عند إنشاء كائن من الكلاس.
هذه الدالة تجعلك قادر على تمرير قيم أولية للكائن بشكل مباشر له لحظة إنشائه.

أهمية الكونستركتور في C++

من أهم الأشياء التي عليك التفكير بها عند إنشاء كلاس جديد, هي تسهيل طريقة إنشاء كائنات من هذا الكلاس لاحقاً.
من هنا جاءت فكرة الكونستركتور ( Constructor ) و الذي هو عبارة عن دالة, يتم إستدعائها أثناء إنشاء كائن من الكلاس لإعطاء قيم أولية للخصائص الموجودة فيه.

أيّ كلاس تقوم بتعريفه, يملك كونستركتور إفتراضي حتى لو تقم بتعريفه له بنفسك و سبب ذلك أنه لا يمكن إنشاء كائن من كلاس إلا من خلال كونستركتور هذا الكلاس.
لهذا إن لم تقم بتعريف كونستركتور للكلاس بنفسك, فكن على يقين أن مترجم لغة C++ سيقوم بإنشاء كونستركتور إفتراضي فارغ بدلاً عنك عندما تحاول إنشاء كائن من الكلاس.


نقاط مهمة حول الكونستركتور

  • كل كلاس يتم إنشاؤه يحتوي على كونستركتور واحد على الأقل. و حتى إن لم تقم بتعريف أي كونستركتور, سيقوم المترجم بإنشاء واحد إفتراضي.

  • في كل مرة يتم إنشاء كائن جديد من كلاس, يجب استدعاء كونستركتور من الكلاس حتى يتم إنشاء هذا الكائن.

  • القاعدة الأساسية عند تعريف كونستركتور هي أنه يجب أن يحمل نفس إسم الكلاس و يكون نوعه public.

  • في حال قمت بتعريف كونستركتور, لن يقوم المترجم بإنشاء واحد إفتراضي, أي لن يعود هناك كونستركتور إفتراضي.

  • يمكنك تعريف أكثر من كونستركتور. و يمكنك دائماً إنشاء كونستركتور فارغ, حتى تستخدمه إن كنت لا تريد إعطاء قيم أولية محددة للخصائص عند إنشاء كائن.



في المثال التالي قمنا بتعريف كلاس إسمه Book و لم نقم بتعريف كونستركتور له.

المثال الأول

		class Book {

		} 
	  

سيقوم المترجم بإنشاء كونستركتور فارغ بشكل تلقائي عنا كالتالي.

		class Book {

		public:
		// هذا كونستركتور إفتراضي أنشأه المترجم لأن الكلاس لا يحتوي على أي كونستركتور
		Book() {

		}

		} 
	  

طريقة استدعاء الكونستركتور في C++

عند استدعاء كونستركتور موجود في كلاس, يجب أن تمرر قيمة لكل باراميتر موجود فيه من خلال وضع قوسين بعد إسم الكائن و تمرير القيم فيه.
فيما ويلي وضعنا بعض الأمثلة التي توضح كيفية إستتدعاء كونستركتور من الكلاس.


إذا كان إسم الكونستركتور هكذا Book() فإنك لا تحتاج فعل أي شيء حين تنشئ كائن من الكلاس حيث تنشئه كالتالي.

المثال الأول

		Book book;
	  

إذا كان إسم الكونستركتور هكذا Book(string title) فإنك مجبر على تمرير قيمة لكونستركتور الكائن كالتالي عند إنشاءه كالتالي.

المثال الثاني

		Book book("C++ for beginners");
	  

إذا كان إسم الكونستركتور هكذا Book(string title, string author) فإنك مجبر على تمرير قيم لكونستركتور الكائن كالتالي عند إنشاءه كالتالي.

المثال الثالث

		Book book("C++ for beginners", "Mhamad Harmush");
	  

إذا كان إسم الكلاس يحتوي على كونستركتور فارغ Book() و كونستركتور يأخذ قيمتين هكذا Book(string title, string author) فهنا تكون مخيّر على استدعاء الكونستركتور الذي تريده منهما عند إنشاء كائن من الكلاس.

المثال الرابع

		// يمكنك أن تنشئ الكائن من خلال استدعاء الكونستركتور الأول كالتالي
		Book book();

		// و يمكنك أن تنشئ الكائن من خلال استدعاء الكونستركتور الثاني كالتالي
		Book book("C++ for beginners", "Mhamad Harmush");
	  

مثال شامل حول التعامل مع الكونستركتور في C++

في المثال التالي, قمنا بتعريف كلاس إسمه Book يمثل المعلومات التي يمكن أن يتضمنها أي كتاب كعنوانه, إسم المؤلف, سعره و عدد صفحاته.
في الكلاس Book قمنا بتعريف كونستركتور يمكننا من خلاله إدخال قيم مباشرةً للخصائص الموجودة في أي كائن ننشئه من الكلاس.
كما أننا قمنا بتعريف دالة إسمها printInfo() عند استدعاءها تقوم بطباعة قيم الخصائص التي يمكلها أي كائن ننشئه من الكلاس.

مثال

main.cpp
		#include <iostream>

		using namespace std;

		// يحتوي على 4 متغيرات Book هنا قمنا بتعريف كلاس إسمه
		class Book {

		public:
		// هنا قمنا بتعريف خصائص الكلاس
		string title;
		string author;
		double price;
		int numberOfPages;

		// هنا قمنا بتعريف كونستركتور يجب تمرير 4 قيم له عندما يتم إستدعاؤه
		Book(string title, string author, double price, int numberOfPages)
		{
		// هنا قمنا بوضع القيم التي نمررها للكونستركتور بالترتيب في خصائص الكائن
		this->title = title;
		this->author = author;
		this->price = price;
		this->numberOfPages = numberOfPages;
		}

		// تقوم بطباعة كل قيم المتغيرات الموجودة فيه Book عند استدعاءها من أي كائن ننشئه من printInfo هنا قمنا بتعريف دالة إسمها
		void printInfo()
		{
		cout << "Title: " << title << "\n";
		cout << "Author: " << author << "\n";
		cout << "Price: " << price << "$\n";
		cout << "Number of pages: " << numberOfPages << "\n";
		}
		};


		// main() هنا قمنا بتعريف الدالة
		int main()
		{
		// مع تمرير القيم التي نريد وضعها فيه بشكل مباشر من خلال الكونستركتور book إسمه Book هنا قمنا بتعريف كائن من
		Book book("C++ for beginners", "Mhamad Harmush", 9.99, 420);

		// حتى تقوم بطباعة القيم الموجودة فيه book من الكائن printInfo() هنا قمنا باستدعاء الدالة
		book.printInfo();

		return 0;
		}
	  

سنحصل على النتيجة التالية عند التشغيل.

		Title: C++ for beginners
		Author: Mhamad Harmush
		Price: 9.99$
		Number of pages: 420
	  


المفهوم الخامس

الدستركتور ( Destructor ) عبارة عن دالة مميزة يتم استدعاؤها بشكل تلقائي عندما يتم مسح الكائن من الذاكرة.
هذه الدالة تجعلك قادر على فعل أي عملية تريدها بشكل مباشر قبل أن يتم حذف الكائن من الذاكرة.

أهمية الدستركتور في C++

الدستركتور ( Destructor ) عبارة عن دالة مميزة يتم استدعاؤها بشكل تلقائي عندما يتم مسح الكائن من الذاكرة.
هذه الدالة تجعلك قادر على فعل أي عملية تريدها بشكل مباشر قبل أن يتم حذف الكائن من الذاكرة.

أيّ كلاس تقوم بتعريفه, يملك ديستكرتور إفتراضي حتى لو تقم بتعريفه له بنفسك و يتم إستدعاؤه بشكل تلقائي مباشرةً إذا قبل أن يتم مسح الكائن من الذاكرة.


نقاط مهمة حول الدستركتور

  • كل كلاس يتم إنشاؤه يحتوي على دستركتور. أي حتى إن لم تقم بتعريف دستركتور بنفسك سيقوم المترجم بإنشاء واحد إفتراضي عنك.

  • الدستركتور يتم إستدعاؤه بشكل تلقائي عندما يتم مسح الكائن من الذاكرة.

  • القاعدة الأساسية عند تعريف دستركتور هي أنه يجب أن يحمل نفس إسم الكلاس و قبله رمز ~ و يكون نوعه public.

  • يمكنك تعريف دستركتور واحد فقط في الكلاس.

  • لا يمكن وضع باراميترات في الدستركتور.



متى يتم استدعاء الدستركتور؟

  • في حال تم إنشاء الكائن بداخل دالة و تم تنفيذ كل محتوى الدالة لأنه من الطبيعي أن يتم حذف أي شيء تم تعريفه فيها بعد أن تتنفذ.

  • في حال تم تنفيذ جميع أوامر البرنامج الموضوعة بداخل الدالة main() لأنه من الطبيعي أن يتم حذف أي شيء تم تعريفه فيها بعد أن تتنفذ.

  • في حال تم حذف الكائن من الذاكرة بأي طريقة أخرى.

أمثلة على الدستركتور في C++

في المثال التالي قمنا بتعريف كلاس إسمه Book و قمنا فيه بتعريف كونستركتور إفتراضي يطبع الجملة "Constructor is called" حين يتم استدعاؤه و دستركتور يقوم بطباعة الجملة "Destructor is called" حين يتم استدعاؤه.

تذكر: الكونستركتور سيتم استدعاؤه حين يتم إنشاء كائن من الكلاس, و الدستركتور سيتم استدعاؤه بشكل تلقائي حين يتم مسح الكائن من الذاكرة.

مثال

main.cpp
		#include <iostream>

		using namespace std;

		// يحتوي على 4 متغيرات Book هنا قمنا بتعريف كلاس إسمه
		class Book {

		public:

		// هنا قمنا بتعريف الكونستركتور الذي سنقوم باستدعائه حين ننشئ كائن من الكلاس
		Book()
		{
		cout << "Constructor is called" << endl;
		}

		// هنا قمنا بتعريف الدستركتور الذي سيتم استدعائه بشكل تلقائي حين يتم حذف الكائن من الذاكرة
		~Book()
		{
		cout << "Destructor is called" << endl;
		}

		};


		// main() هنا قمنا بتعريف الدالة
		int main()
		{
		// و بالتالي سيتم تنفيذ أمر الطباعة الموجود في الكونستركتور Book هنا قمنا بتعريف كائن من
		Book book;

		// بما أن البرنامج إنتهى هنا فهذا يعني أنه سيتم تنفيذ أمر الطباعة الموجود في الدستركتور
		return 0;
		}
	  

سنحصل على النتيجة التالية عند التشغيل.

		Constructor is called
		Destructor is called
	  


المفهوم السادس

الدالة الصديقة ( Friend Function ) عبارة عن دالة يمكنها الوصول لأي شيء يمكله الكائن حتى إن كائن في الكلاس نوعه private أو protected.

مقهوم الدالة الصديقة في C++

الدالة الصديقة ( Friend Function ) عبارة عن دالة يمكنها الوصول لأي شيء يمكله الكائن حتى إن كائن في الكلاس نوعه private أو protected.


شروط تعريف دالة صديقة

  • أن يتم وضع شكل الدالة ( Prototype ) فقط بداخل الكلاس و محتواها ( Body ) خارج الكلاس.

  • عند وضع شكل الدالة بداخل الكلاس يجب أن تذكر الكلمة friend و لكن لا يجب أن تذكرها عندما تكتب محتوى الدالة خارج الكلاس.

  • في الكلاس لا يهم المكان الذي تقوم فيه بوضع شكل الدالة ( Prototype ), أي لا يهم إن جعلتها public أو private أو protected.

  • محتوى الدالة ( Function Body ) يجب تعريفه خارج الكلاس.

  • أن تكون الدالة تملك باراميتر عبارة عن كائن من الكلاس الذي تنوي الوصول لأي شيء موجود فيه.

مثال شامل حول تعريف دالة صديقة في C++

في المثال التالي, قمنا بتعريف كلاس إسمه Demo يحتوي على 4 متغيرات كل واحد منهم له Modifier مختلف.
بعدها قمنا بتعريف دالة صديقة إسمها printValues عند استدعاءها نمرر لها كائن من الكلاس Demo فتقوم بطباعة قيمه بشكل مرتب.

في الأخير قمنا بإنشاء كائن من Demo و إعطاؤه قيم, و من ثم إستدعاء الدالة printValues() منه حتى تقوم بطباعة قيمه.

مثال

main.cpp
		#include <iostream>

		using namespace std;

		// يحتوي على 4 متغيرات و دالة صديقة Demo هنا قمنا بتعريف كلاس إسمه
		class Demo {

		// printValues هنا قمنا بتعريف شكل الدالة الصديقة
		friend void printValues(Demo demo);

		int a = 1;

		public:
		int b = 2;

		private:
		int c = 3;

		protected:
		int d = 4;
		};

		// في أولها friend و لاحظ أننا لم نضع الكلمة printValues هنا قمنا بتعريف محتوى الدالة الصديقة
		void printValues(Demo demo)
		{
		cout << "a = " << demo.a << "\n";
		cout << "b = " << demo.b << "\n";
		cout << "c = " << demo.c << "\n";
		cout << "d = " << demo.d << "\n";
		}

		// main() هنا قمنا بتعريف الدالة
		int main()
		{
		// demo إسمه Demo هنا قمنا بتعريف كائن من
		Demo demo;

		// لها حتى تقوم بطباعة القيم الموجودة فيه demo و تمرير الكائن printValues() هنا قمنا باستدعاء الدالة
		printValues(demo);

		return 0;
		}
	  

سنحصل على النتيجة التالية عند التشغيل.

		a = 1
		b = 2
		c = 3
		d = 4
	  


المفهوم السابع

هنا وضعنا مثال حول كيفية تعريف دالة تأخذ باراميتر نوعه مؤشر لكائن من كلاس ( Pointer to class ) بالإضافة إلى كيفية إستدعاءها.

التعامل مع مؤشر لكلاس هو نفسه تماماً التعامل مع مؤشر لـ struct.
إذاً للوصول للأشياء الموجودة في مؤشر لكائن من كلاس نستخدم العامل -> و ليس العامل . المعتاد.


في المثال التالي, قمنا بتعريف كلاس إسمه Book يمثل المعلومات التي يمكن أن يتضمنها أي كتاب كعنوانه, إسم المؤلف, سعره و عدد صفحاته.
بعدها قمنا بتعريف دالة إسمها printInfo عند استدعاءها نمرر لها عنوان كائن من Book موجود في الذاكرة فتقوم بطباعة قيمه بشكل مرتب.

في الأخير قمنا بإنشاء كائن من Book و إعطاؤه قيم, و من ثم تمرير عنوانه في الذاكرة للدالة printInfo() حتى تقوم بطباعة قيمه.

مثال

		#include <iostream>

		using namespace std;

		// يحتوي على 4 متغيرات Book هنا قمنا بتعريف كلاس إسمه
		class Book {

		public:
		string title;
		string author;
		double price;
		int numberOfPages;

		};

		// فتقوم بطباعة كل قيم المتغيرات الموجودة فيه Book عند استدعاءها نمرر لها عنوان كائن من printInfo هنا قمنا بتعريف دالة إسمها
		void printInfo(Book* book)
		{
		cout << "Title: " << book->title << "\n";
		cout << "Author: " << book->author << "\n";
		cout << "Price: " << book->price << "$\n";
		cout << "Number of pages: " << book->numberOfPages << "\n";
		}

		// main() هنا قمنا بتعريف الدالة
		int main()
		{
		// book إسمه Book هنا قمنا بتعريف كائن من
		Book book;

		// book هنا قمنا بإعطاء قيم لمتغيرات الكائن
		book.title = "C++ for beginners";
		book.author = "Mhamad Harmush";
		book.price = 9.99;
		book.numberOfPages = 420;

		// لها حتى تقوم بطباعة القيم الموجودة فيه book و تمرير عنوان الكائن printInfo() هنا قمنا باستدعاء الدالة
		printInfo(&book);

		return 0;
		}
	  

سنحصل على النتيجة التالية عند التشغيل.

		Title: C++ for beginners
		Author: Mhamad Harmush
		Price: 9.99$
		Number of pages: 420
	  


المفهوم الثامن

الأشياء المشتركة ( Static Members ) عبارة عن أي شيء يتم تعريفه في الكلاس بشكل يكون موّحداً بالنسبة لجميع الكائنات التي يتم إنشاءها منه.

مفهوم الأشياء المشتركة في C++

الأشياء المشتركة ( Static Members ) عبارة عن أي شيء يتم تعريفه في الكلاس بشكل يكون موّحداً بالنسبة لجميع الكائنات التي يتم إنشاءها منه.
بشكل عام لجعل الشيئ الذي يتم تعريفه في الكلاس مشترك بين جميع الكائنات التي قد ننشئها منه نستخدم الكلمة static كما سنرى بعد قليل في الأمثلة.


فوائد الأشياء المشتركة

الأشياء المشتركة لها عدة استخدامات و فوائد فعلى سبيل المثال إذا أردت جميع الكائنات التي يتم إنشاءها من كلاس محدد تملك نفس قيمة متغير موجود في هذا الكلاس, يمكنك جعل نوع المتغير static و عندها سيصبج مشترك بين جميع الكائنات.

من ناحية الذاكرة, بما أن المتغير المشترك يكون نفسه موضوع لجميع الكائنات التي يتم إنشاؤها من نفس الكلاس, فهذا يعني أنك لو قمت بإنشاء 50 كائن من الكلاس فإنه لن يتم إنشاء 50 نسخة من المتغير في الذاكرة, بل سيكون هناك نسخة واحدة منه مشتركة بين جميع الكائنات.

في هذا الدرس سنتعرف على كيفية تعريف متغيرات و دوال مشتركة و كيفية التعامل معها.

المتغيرات المشتركة

تعريف المتغير في الكلاس كمتغير مشترك يجعلك قادر على الوصول لقيمة هذا المتغير بشكل مباشر من الكلاس, أي بدون الحاجة لإنشاء كائن منه.
عند تعريف المتغير المشترك, لا يسمح لك بإعطائه قيمة أولية بداخل الكلاس حيث أنك يجب أن تعطيه قيمة أولية خارج الكلاس.

بعد إسناد قيمة أولية للمتغير المشترك, تستطيع تغيير قيمته لاحقاً من خلال أي كائن يمكنه الوصول إليها.


المتغير المشترك يجب تعريفه على مرحتلين:

  • يجب تعريفه بداخل الكلاس بدون إعطائه قيمة أولية مع الإشارة إلى أنه يجب تحديد نوعه static.

  • يجب إعطاؤه قيمة أولية خارج الكلاس.



في المثال التالي, قمنا بتعريف كلاس إسمه Demo يحتوي على متغير عادي إسمه x و متغير مشترك إسمه y.
المتغير المشترك y قمنا بإعطائه 0 كقيمة أولية خارج الكلاس كما يفترض.
بعدها قمنا بإنشاء ثلاث كائنات من الكلاس Demo و إعطاء قيمة مختلفة للمتغير x الخاص بكل الكائن.
في النهاية قمنا بتغيير قيمة المتغير المشترك y مرة واحدة حتى نلاحظ كيف أنها تغيرت بالنسبة لجميع الكائنات.

مثال

main.cpp
		#include <iostream>

		using namespace std;

		// Demo هنا قمنا بتعريف الكلاس
		class Demo {

		// y و المتغير المشترك x هنا قمنا بتعريف المتغير
		public:
		int x;
		static int y;

		};

		// القيمة 0 كقيمة أولية y هنا قمنا بإعطاء المتغير المشترك
		int Demo::y = 0;

		// main() هنا قمنا بتعريف الدالة
		int main()
		{
		// Demo هنا قمنا بتعريف ثلاث كائنات من الكلاس
		Demo demo1, demo2, demo3;

		// التي يملكها كل كائن قمنا بإنشائه x هنا قمنا بتغيير قيمة المتغير
		demo1.x = 10;
		demo2.x = 20;
		demo3.x = 30;

		// التي يملكها كل كائن قمنا بإنشائه x هنا قمنا بطباعة قيمة المتغير
		cout << "demo1.x = " << demo1.x << endl;
		cout << "demo2.x = " << demo2.x << endl;
		cout << "demo3.x = " << demo3.x << endl;

		// التي هي نفسها لكل الكائنات و بالطبع الآن قيمته هي 0 لأننا لم نقم بتغيير قيمته الأولية y هنا قمنا بطباعة قيمة المتغير المشترك
		cout << "Demo.y = " << demo1.y << endl;
		cout << "Demo.y = " << demo2.y << endl;
		cout << "Demo.y = " << demo3.y << endl;

		// demo1 إلى 5 من خلال الكائن y هنا قمنا بتغيير قيمة
		// سيتم إعتبار أنها تغييرت بالنسبة لجميع الكائنات لأنها مشتركة فيما بينهم demo3 أو demo2 أو demo1 ملاحظة: سواء غيرناها من خلال الكائن
		demo1.y = 5;

		// demo1 من جديد للتأكد ما إن كانت حقاً أصبحت تساوي 5 أم لا بالنسبة لجميع الكائنات و ليس فقط الكائن y هنا قمنا بطباعة قيمة المتغير المشترك
		cout << "Demo.y = " << demo1.y << endl;
		cout << "Demo.y = " << demo2.y << endl;
		cout << "Demo.y = " << demo3.y << endl;

		return 0;
		}

	  

سنحصل على النتيجة التالية عند التشغيل.

		demo1.x = 10
		demo2.x = 20
		demo3.x = 30
		Demo.y = 0
		Demo.y = 0
		Demo.y = 0
		Demo.y = 5
		Demo.y = 5
		Demo.y = 5
	  

الدوال المشتركة

فكرة الدوال المشتركة ببساطة هي تعريف دالة في كلاس يمكن استدعاءها بشكل مباشر منه بدون الحاجة لإنشاء كائن منه.
الدالة التي يتم تعريفها كدالة مشتركة يمكنها فقط التعامل مع المتغيرات المشتركة, أي التي نوعها static مثلها.

بالنسبة لطريقة تعريف دالة مشتركة فهي نفسها طريقة تعريف دالة عادية مع إضافة الكلمة static إليها.



في المثال التالي, سنستخدم متغير و دالة مشتَركين لمعرفة عدد الكائنات التي يتم إنشاؤها من الكلاس.

في البداية قمنا بتعريف كلاس إسمه Demo يحتوي على متغير مشترك إسمه counter و دالة مشتركة إسمها getCounter عند استدعاءها تقوم بإرجاع قيمة المتغير counter فقط.

في الكلاس Demo قمنا بتعديل الكونستركتور الإفتراضي لجعله يقوم بإضافة 1 على قيمة المتغير counter كلما تم إستدعاؤه.
بمعنى آخر, كلما قمنا بإنشاء كائن - من خلال الكونستركتور الإفتراضي - سيتم إضافة 1 على قيمة المتغير counter و بالتالي فإن قيمة coutner ستمثل عدد الكائنات التي يتم إنشاءها من الكلاس Demo.

في النهاية قمنا بإنشاء ثلاث كائنات من الكلاس Demo و من ثم إستدعاء الدالة getCounter() لمعرفة عدد الكائنات التي تم إنشاؤها.

مثال

main.cpp
		#include <iostream>

		using namespace std;

		// Demo هنا قمنا بتعريف الكلاس
		class Demo {

		public:
		// counter هنا قمنا بتعريف المتغير المشترك
		static int counter;

		// كلما تم استدعاؤه counter هنا قمنا بتعريف الكونستركتور و جعلناه يزيد 1 على قيمة المتغير المشترك
		Demo()
		{
		counter++;
		}

		// فقط عندما يتم استدعاءها counter و قلنا أنها ترجع قيمة المشترك getCounter() هنا قمنا بتعريف الدالة المشتركة
		static int getCounter()
		{
		return counter;
		}

		};


		// القيمة 0 كقيمة أولية counter هنا قمنا بإعطاء المتغير المشترك
		int Demo::counter = 0;

		// main() هنا قمنا بتعريف الدالة
		int main()
		{
		// Demo هنا قمنا بتعريف ثلاث كائنات من الكلاس
		Demo demo1, demo2, demo3;

		// لطباعة عدد الكائنات التي تم إنشاءها منه Demo من الكلاس getCounter() هنا قمنا باستدعاء الدالة
		cout << "total created object = " << Demo::getCounter();

		return 0;
		}

	  

سنحصل على النتيجة التالية عند التشغيل.

		total created object = 3