C++: تمرين: البرمجة كائنية التوجه الشامل
آخر تحديث: 2026-08-26
في الدروس الـ 35 السابقة، غطينا جوانب عديدة من C++.
الآن، حان وقت الجمع بين كل شيء.
في هذا الدرس، سنبنى نظام إدارة طلاب كامل — من تحليل المتطلبات إلى تنفيذ الكود، مع تجربة تطوير البرمجيات الحقيقية.
1. تحليل متطلبات المشروع
(1) 1.1 المتطلبات الوظيفية
نظام إدارة الطلاب الذي نبناه له الميزات التالية:
| وحدة الميزات | الوظائف المحددة |
|---|---|
| إدارة الطلاب | إضافة، حذف، تعديل، بحث الطلاب |
| إدارة الدرجات | إدخال الدرجات، حساب المتوسطات، الترتيب |
| الثبات البياني | حفظ في ملف، تحميل من ملف |
| واجهة المستخدم | واجهة طرفية بقوائم |
(2) 1.2 تصميم الأصناف
بناءً على المتطلبات، نحتاج لتصميم الأصناف التالية:
Student (الصنف الأساسي)
↑ يرث
UndergraduateStudent (طالب جامعي)
GraduateStudent (طالب دراسات عليا)
Course (صنف المقرر)
Grade (صنف الدرجة)
ManagementSystem (صنف نظام الإدارة)
- vector<Student*> students
- vector<Course> courses
2. تنفيذ النسخة الأساسية
(1) 2.1 تصميم صنف الطالب
مثال: صنف الطالب النسخة الأساسية (الصعوبة ⭐⭐)
#include <iostream>
#include <string>
#include <vector>
// صنف الطالب الأساسي
class Student {
protected:
std::string id; // رقم الطالب
std::string name; // الاسم
int age; // العمر
std::string major; // التخصص
public:
// المُنشئ
Student(const std::string& id, const std::string& name, int age, const std::string& major)
: id(id), name(name), age(age), major(major) {}
// دالة افتراضية: عرض المعلومات
virtual void display() const {
std::cout << "Student ID: " << id << std::endl;
std::cout << "Name: " << name << std::endl;
std::cout << "Age: " << age << std::endl;
std::cout << "Major: " << major << std::endl;
}
// مدمر افتراضي
virtual ~Student() {}
// الحاصلات
std::string getId() const { return id; }
std::string getName() const { return name; }
};
// صنف الطالب الجامعي
class UndergraduateStudent : public Student {
private:
int year; // السنة (1-4)
public:
UndergraduateStudent(const std::string& id, const std::string& name,
int age, const std::string& major, int year)
: Student(id, name, age, major), year(year) {}
void display() const override {
Student::display();
std::cout << "Year: " << year << std::endl;
std::cout << "Type: Undergraduate" << std::endl;
}
};
// صنف طالب الدراسات العليا
class GraduateStudent : public Student {
private:
std::string advisor; // المشرف
public:
GraduateStudent(const std::string& id, const std::string& name,
int age, const std::string& major, const std::string& advisor)
: Student(id, name, age, major), advisor(advisor) {}
void display() const override {
Student::display();
std::cout << "Advisor: " << advisor << std::endl;
std::cout << "Type: Graduate Student" << std::endl;
}
};
(2) 2.2 صنف نظام الإدارة
مثال: نظام الإدارة النسخة الأساسية (الصعوبة ⭐⭐⭐)
▶ مثال 1: استخدام حاويات STL (الصعوبة ⭐)
class ManagementSystem {
private:
std::vector<Student*> students; // قائمة الطلاب (تعدد الأشكال)
public:
// إضافة طالب
void addStudent(Student* student) {
students.push_back(student);
std::cout << "Added successfully!" << std::endl;
}
// البحث عن طالب
Student* findStudent(const std::string& id) {
for (auto s : students) {
if (s->getId() == id) {
return s;
}
}
return nullptr;
}
// عرض جميع الطلاب
void displayAll() const {
if (students.empty()) {
std::cout << "No student information available" << std::endl;
return;
}
for (auto s : students) {
s->display();
std::cout << "-------------------" << std::endl;
}
}
// المدمر: تحرير الذاكرة
~ManagementSystem() {
for (auto s : students) {
delete s;
}
}
};
// كود الاختبار
int main() {
ManagementSystem sys;
// إضافة طالب جامعي
sys.addStudent(new UndergraduateStudent("001", "Zhang San", 20, "Computer Science", 3));
sys.addStudent(new GraduateStudent("002", "Li Si", 24, "Software Engineering", "Prof. Wang"));
// عرض جميع الطلاب
sys.displayAll();
return 0;
}
الخرج:
Added successfully!
No student information available
-------------------
نتيجة التشغيل:
Added successfully!
Added successfully!
Student ID: 001
Name: Zhang San
Age: 20
Major: Computer Science
Year: 3
Type: Undergraduate
-------------------
Student ID: 002
Name: Li Si
Age: 24
Major: Software Engineering
Advisor: Prof. Wang
Type: Graduate Student
-------------------
3. تنفيذ النسخة الكاملة
(1) 3.1 إضافة ميزات أخرى
الآن، لنضيف ميزات أخرى للنظام:
| الميزة | التنفيذ |
|---|---|
| حذف طالب | حذف برقم الطالب |
| تعديل المعلومات | البحث برقم الطالب، ثم التعديل |
| إدارة الدرجات | إضافة صنف Grade |
| الحفظ في ملف | استخدام ofstream لكتابة ملف |
| التحميل من ملف | استخدام ifstream لقراءة ملف |
(2) 3.2 تصميم صنف الدرجة
// صنف الدرجة
### ▶ مثال 2: عرض البرمجة كائنية التوجه (الصعوبة ⭐)
class Grade {
private:
std::string courseId; // رقم المقرر
std::string courseName; // اسم المقرر
double score; // الدرجة
public:
Grade(const std::string& courseId, const std::string& courseName, double score)
: courseId(courseId), courseName(courseName), score(score) {}
void display() const {
std::cout << courseName << ": " << score << " points" << std::endl;
}
double getScore() const { return score; }
};
// إضافة طرق متعلقة بالدرجات لصنف Student
class Student {
// ... أعضاء آخرون ...
std::vector<Grade> grades; // قائمة الدرجات
public:
void addGrade(const Grade& grade) {
grades.push_back(grade);
}
void displayGrades() const {
if (grades.empty()) {
std::cout << "No grades available" << std::endl;
return;
}
std::cout << name << "'s grades:" << std::endl;
for (const auto& g : grades) {
g.display();
}
}
double getAverage() const {
if (grades.empty()) return 0.0;
double sum = 0;
for (const auto& g : grades) {
sum += g.getScore();
}
return sum / grades.size();
}
};
(3) 3.3 عمليات الملفات
حفظ معلومات الطلاب في ملف:
void saveToFile(const std::string& filename) {
std::ofstream file(filename);
if (!file) {
std::cout << "Cannot open file" << std::endl;
return;
}
for (auto s : students) {
file << s->getId() << ","
<< s->getName() << ","
<< s->getAge() << std::endl;
}
file.close();
std::cout << "Saved successfully!" << std::endl;
}
التحميل من ملف:
void loadFromFile(const std::string& filename) {
std::ifstream file(filename);
if (!file) {
std::cout << "Cannot open file" << std::endl;
return;
}
std::string id, name, ageStr;
while (std::getline(file, id, ',')) {
std::getline(file, name, ',');
std::getline(file, ageStr);
int age = std::stoi(ageStr);
// إنشاء كائن طالب (مبسط؛ يجب التمييز بين جامعي/دراسات عليا)
students.push_back(new UndergraduateStudent(id, name, age, "Unknown", 1));
}
file.close();
std::cout << "Loaded successfully!" << std::endl;
}
4. تنفيذ واجهة القائمة
(1) 4.1 القائمة الرئيسية
void showMenu() {
std::cout << "\n===== Student Management System =====" << std::endl;
std::cout << "1. Add student" << std::endl;
std::cout << "2. Find student" << std::endl;
std::cout << "3. Display all students" << std::endl;
std::cout << "4. Enter grades" << std::endl;
std::cout << "5. Save data" << std::endl;
std::cout << "6. Load data" << std::endl;
std::cout << "0. Exit" << std::endl;
std::cout << "=====================================" << std::endl;
std::cout << "Choose: ";
}
int main() {
ManagementSystem sys;
int choice;
do {
showMenu();
std::cin >> choice;
switch (choice) {
case 1:
// إضافة طالب
break;
case 2:
// البحث عن طالب
break;
case 3:
sys.displayAll();
break;
case 0:
std::cout << "Goodbye!" << std::endl;
break;
default:
std::cout << "Invalid choice" << std::endl;
}
} while (choice != 0);
return 0;
}
5. اقتراحات توسيع المشروع
(1) 5.1 توسيعات الميزات
| الميزة | الصعوبة | الوصف |
|---|---|---|
| إحصائيات الدرجات | ⭐⭐ | حساب المتوسطات، الترتيب |
| التحقق من البيانات | ⭐⭐ | التحقق من صحة الإدخال |
| معالجة الاستثناءات | ⭐⭐⭐ | استخدام try-catch للأخطاء |
| واجهة رسومية | ⭐⭐⭐⭐ | استخدام Qt أو wxWidgets |
| قاعدة بيانات | ⭐⭐⭐⭐ | استخدام SQLite أو MySQL |
(2) 5.2 تحسين الكود
| التحسين | الوصف |
|---|---|
| المؤشرات الذكية | استخدام unique_ptr لإدارة الذاكرة |
| صحة الثوابت | استخدام const حيثما أمكن |
| معالجة الاستثناءات | استخدام try-catch لأخطاء الملفات |
| التحميل الزائد للعوامل | تحميل زائد << للخرج |
▶ مثال 3: تسلسل وراثة أصناف بسيط (الصعوبة ⭐)
#include <iostream>
#include <string>
class Animal {
public:
std::string name;
Animal(const std::string& n) : name(n) {}
virtual void speak() const = 0;
virtual ~Animal() {}
};
class Dog : public Animal {
public:
Dog(const std::string& n) : Animal(n) {}
void speak() const override {
std::cout << name << ": Woof!" << std::endl;
}
};
class Cat : public Animal {
public:
Cat(const std::string& n) : Animal(n) {}
void speak() const override {
std::cout << name << ": Meow!" << std::endl;
}
};
int main() {
Dog dog("Wangcai");
Cat cat("Mimi");
dog.speak();
cat.speak();
return 0;
}
الخرج:
: Woof!
: Meow!
❓ أسئلة شائعة
س: لماذا نستخدم مؤشرات لتخزين الطلاب؟ ج: لتحقيق تعدد الأشكال. استخدام
vector<Student>سيسبب تقطيع الكائنات، لذا يمكن فقط استدعاء دوال الصنف الأساسي.
س: ماذا عن تسرب الذاكرة؟ ج: استخدم المؤشرات الذكية (
unique_ptr) لإدارة الذاكرة تلقائيًا — لا حاجة لـdeleteيدوي.
س: كيف يجب أن أصمم تنسيق الملف؟ ج: يمكنك استخدام: - تنسيق CSV: بسيط، لكن وظائف محدودة - تنسيق JSON: قوي، يحتاج مكتبة خارجية - تنسيق ثنائي: فعال، لكن غير قابل للقراءة البشرية
wstring + wcout - أو استخدم مكتبة خارجية (مثلاً iconv) - أو خزّن البينيين/الإنجليزية فقط📖 ملخص
| نقطة المعرفة | الاستنتاج الرئيسي |
|---|---|
| تصميم الأصناف | صنف أساسي + صنف مشتق، يعكس الوراثة |
| تعدد الأشكال | استخدام مؤشرات/مراجع لاستدعاء دوال افتراضية |
| عمليات الملفات | ofstream للكتابة، ifstream للقراءة |
| إدارة الذاكرة | المدمر يحرر الذاكرة (أو استخدم المؤشرات الذكية) |
| واجهة القائمة | do-while + switch |
اقتراحات الدراسة:
- هذا المشروع تمرين شامل — تأكد من كتابته بنفسك
- نفّذ الميزات الأساسية أولاً، ثم وسّع تدريجيًا
- عند مواجهة مشاكل، ابحث عن حلول أولاً — طوّر مهارات حل المشكلات
📝 تمارين
-
أساسي (الصعوبة ⭐): عرّف صنف كتاب (عنوان، مؤلف، سعر)، أنشئ 3 كائنات وأخرج خصائصها.
-
متوسط (الصعوبة ⭐⭐): نفذ تسلسلًا وراثيًا: Shape (صنف أساسي، دالة افتراضية نقية area()) → صنفين مشتقين Circle وRectangle. استدعِ area() بتعدد الأشكال.
-
متقدم (الصعوبة ⭐⭐⭐): نفذ "نمط المراقب": صنف Subject يحتفظ بقائمة Observer، Observer صنف أساسي مجرد. عند تغير حالة Subject، أبلغ جميع المراقبين.
- غطى هذا القسم المفاهيم الأساسية لتطبيق OOP
- مع الإتقان، يمكنك كتابة برامج C++ ذات صلة
اكتملت المرحلة 5! التالي: المرحلة 6 (STL المتقدم)