C++: أساسيات البنى
آخر تحديث: 2026-08-26
يمكن للمصفوفات تخزين قيم متعددة من نوع واحد، لكن ماذا لو احتجت إلى تخزين اسم الطالب (نص)، العمر (عدد صحيح)، الدرجة (عدد عشري)؟
هنا تأتي البنى — التي تجمع متغيرات متعددة من أنواع مختلفة في وحدة واحدة.
1. ما هي البنية؟
(1) 1.1 البنى في الحياة اليومية
| مثال من الحياة اليومية | المكافئ البرمجي |
|---|---|
| بطاقة عمل (الاسم، الهاتف، البريد الإلكتروني) | بنية |
| كتاب (العنوان، المؤلف، السعر) | بنية |
| طالب (الاسم، العمر، الدرجة) | بنية |
خصائص البنى:
- يمكن أن يكون للأعضاء أنواع مختلفة
- ذاكرة متجاورة (مثل المصفوفات)
- مقدمة للفئات (ستتعلم الفئات لاحقاً)
(2) 1.2 لماذا نحتاج البنى؟
بدون البنى (ممل):
▶ مثال 2: مثال برمجي (الصعوبة ⭐)
#include <iostream>
#include <string>
int main() {
std::string name1 = "Alice";
int age1 = 20;
double score1 = 92.5;
std::string name2 = "Bob";
int age2 = 21;
double score2 = 88.0;
// ... ستحتاج إلى تعريف 3 × 100 متغير!
return 0;
}
الخرج:
(program output)
مع البنى (موجز):
#include <iostream>
#include <string>
struct Student {
std::string name;
int age;
double score;
};
int main() {
Student s1 = {"Alice", 20, 92.5};
Student s2 = {"Bob", 21, 88.0};
// ... أنظف بكثير!
return 0;
}
2. تعريف البنية والإعلان عنها
(1) 2.1 الإعلان عن بنية
الصياغة:
struct StructName {
memberType1 memberName1;
memberType2 memberName2;
...
};
مثال:
#include <iostream>
#include <string>
// الإعلان عن بنية
struct Student {
std::string name;
int age;
double score;
}; // ⚠️ ملاحظة: الفاصلة المنقوطة مطلوبة!
int main() {
// ...
return 0;
}
💡 نقطة مهمة: ينتهي إعلان البنية بـ فاصلة منقوطة! هذا خطأ شائع بين المبتدئين.
3. إنشاء وتهيئة متغيرات البنية
(1) 3.1 إنشاء متغير بنية
Student s1; // إنشاء متغير s1 من نوع Student
(2) 3.2 تهيئة متغير بنية
الطريقة 1: التهيئة بترتيب الإعلان
Student s1 = {"Alice", 20, 92.5};
الطريقة 2: تهيئة الأعضاء المعينة (C++20، موصى بها)
Student s1 = {.name = "Alice", .age = 20, .score = 92.5};
الطريقة 3: تعيين القيم بشكل فردي
Student s1;
s1.name = "Alice";
s1.age = 20;
s1.score = 92.5;
💡 نصيحة: يُنصح بالطريقة 1 أو الطريقة 2 للإيجاز.
4. الوصول إلى أعضاء البنية
(1) 4.1 قراءة الأعضاء
الصياغة:
structName.memberName
مثال:
#include <iostream>
#include <string>
struct Student {
std::string name;
int age;
double score;
};
int main() {
Student s1 = {"Alice", 20, 92.5};
std::cout << "Name: " << s1.name << std::endl; // Alice
std::cout << "Age: " << s1.age << std::endl; // 20
std::cout << "Score: " << s1.score << std::endl; // 92.5
return 0;
}
(2) 4.2 تعديل الأعضاء
Student s1 = {"Alice", 20, 92.5};
s1.score = 95.0; // تعديل الدرجة
std::cout << "New score: " << s1.score << std::endl; // 95.0
5. تمرير البنى كمعاملات دالة
(1) 5.1 التمرير بالقيمة (غير موصى به)
void printStudent(Student s) { // ❌ تمرير بالقيمة: ينسخ البنية بالكامل، مكلف
std::cout << "Name: " << s.name << std::endl;
}
(2) 5.2 التمرير بالمرجع (موصى به)
void printStudent(const Student& s) { // ✅ تمرير بالمرجع: لا نسخ، ولا يمكن التعديل
std::cout << "Name: " << s.name << std::endl;
std::cout << "Age: " << s.age << std::endl;
std::cout << "Score: " << s.score << std::endl;
}
💡 القاعدة الذهبية: عند تمرير بنية كمعامل، يُفضّل المرجع const — فهو يتجنب تكلفة النسخ ويمنع التعديل العرضي.
6. مصفوفات البنى
يمكن أيضاً تنظيم البنى في مصفوفات!
مثال: مصفوفة الطلاب (الصعوبة ⭐⭐)
#include <iostream>
#include <string>
struct Student {
std::string name;
int age;
double score;
};
int main() {
Student students[3] = {
{"Alice", 20, 92.5},
{"Bob", 21, 88.0},
{"Charlie", 19, 95.0}
};
// المرور على مصفوفة البنى
for (int i = 0; i < 3; i++) {
std::cout << "========== Student " << i + 1 << " ==========" << std::endl;
std::cout << "Name: " << students[i].name << std::endl;
std::cout << "Age: " << students[i].age << std::endl;
std::cout << "Score: " << students[i].score << std::endl;
std::cout << std::endl;
}
return 0;
}
7. تطبيق: إدارة درجات الطلاب (نسخة البنى)
▶ مثال 1: إدارة درجات الطلاب الكاملة (الصعوبة ⭐⭐⭐)
#include <iostream>
#include <string>
#include <vector> // سنتعلم vector لاحقاً، نستخدم المصفوفة حالياً
struct Student {
std::string name;
int age;
double score;
};
// إعلان الدوال
void addStudent(Student students, int& count);
void printStudents(const Student students, int count);
double calculateAverage(const Student students, int count);
int main() {
const int MAX_STUDENTS = 100;
Student students[MAX_STUDENTS];
int count = 0;
int choice;
do {
std::cout << "========== Student Score Management ==========" << std::endl;
std::cout << "1. Add student" << std::endl;
std::cout << "2. Display all students" << std::endl;
std::cout << "3. CalculateAverage" << std::endl;
std::cout << "4. Exit" << std::endl;
std::cout << "Please select (1-4): ";
std::cin >> choice;
if (choice == 1) {
addStudent(students, count);
} else if (choice == 2) {
printStudents(students, count);
} else if (choice == 3) {
if (count == 0) {
std::cout << "No student data!" << std::endl;
} else {
std::cout << "Average: " << calculateAverage(students, count) << std::endl;
}
} else if (choice == 4) {
std::cout << "Goodbye!" << std::endl;
} else {
std::cout << "Error: Please enter 1-4 a number between 1-4!" << std::endl;
}
std::cout << std::endl;
} while (choice != 4);
return 0;
}
// تعريف الدوال
void addStudent(Student students, int& count) {
if (count >= 100) {
std::cout << "Maximum number of students reached!" << std::endl;
return;
}
std::cout << "Please enter your name: ";
std::cin.ignore();
std::getline(std::cin, students[count].name);
std::cout << "Please enter your age: ";
std::cin >> students[count].age;
std::cout << "Please enter score: ";
std::cin >> students[count].score;
count++;
std::cout << "Added successfully!" << std::endl;
}
void printStudents(const Student students, int count) {
if (count == 0) {
std::cout << "No student data!" << std::endl;
return;
}
std::cout << "\n========== Student List ==========" << std::endl;
for (int i = 0; i < count; i++) {
std::cout << i + 1 << ". Name: " << students[i].name
<< ",Age: " << students[i].age
<< ",Score: " << students[i].score << std::endl;
}
std::cout << "================================\n\n";
}
double calculateAverage(const Student students, int count) {
if (count == 0) {
return 0.0;
}
double sum = 0.0;
for (int i = 0; i < count; i++) {
sum += students[i].score;
}
return sum / count;
}
الخرج:
========== Student Score Management ==========
1. Add student
2. Display all students
3. CalculateAverage
4. Exit
Please select (1-4):
No student data!
Average:
Goodbye!
Error: Please enter 1-4 a number between 1-4!
Maximum number of students reached!
Please enter your name:
Please enter your age:
Please enter score:
Added successfully!
No student data!
========== Student List ==========
. Name:
==============================
▶ مثال 3: البنية كقيمة إرجاع لدالة (الصعوبة ⭐)
#include <iostream>
#include <string>
struct Student {
std::string name;
int age;
double score;
};
// دالة تُرجع بنية
Student createStudent(std::string n, int a, double s) {
Student stu;
stu.name = n;
stu.age = a;
stu.score = s;
return stu;
}
int main() {
Student s1 = createStudent("Zhang San", 20, 92.5);
std::cout << "Name: " << s1.name << std::endl;
std::cout << "Age: " << s1.age << std::endl;
std::cout << "Score: " << s1.score << std::endl;
return 0;
}
الخرج:
Name:
Age:
Score:
8. الأخطاء الشائعة
(1) 8.1 نسيان الفاصلة المنقوطة
مثال خاطئ:
struct Student { // ❌ نسيت الفاصلة المنقوطة
std::string name;
int age;
} // ❌ يجب أن تكون فاصلة منقوطة هنا
int main() {
// ...
}
رسالة خطأ المترجم:
error: expected ';' after struct definition
(2) 8.2 الوصول إلى عضو غير موجود
مثال خاطئ:
struct Student {
std::string name;
int age;
};
int main() {
Student s1;
s1.score = 92.5; // ❌ خطأ: Student لا يملك عضو score
return 0;
}
❓ أسئلة شائعة
struct على وصول افتراضي public > - يحتوي class على وصول افتراضي privateس: ما أهم شيء في أساسيات البنى؟ ج: افهم المفاهيم الأساسية أولاً، ثم عززها من خلال أمثلة التطبيق.
📖 ملخص
- البنى تجمع متغيرات متعددة من أنواع مختلفة في وحدة واحدة
- إعلان بنية:
struct StructName { member list };(لاحظ الفاصلة المنقوطة!) - التهيئة:
StructName variableName = {value1, value2, ...}; - الوصول للأعضاء:
variableName.memberName - عند التمرير كمعامل، يُفضّل المرجع
const - يمكن أيضاً تنظيم البنى في مصفوفات
📝 تمارين
-
أساسي (الصعوبة ⭐): عرّف بنية
Bookبثلاثة أعضاء: العنوان، المؤلف، والسعر. أنشئ متغيرينBookوأخرجهما. -
متوسط (الصعوبة ⭐⭐): عرّف بنية
Rectangleبعضوين: العرض والارتفاع. -
اكتب دالة
double calculateArea(const Rectangle& r)لحساب المساحة -
اكتب دالة
double calculatePerimeter(const Rectangle& r)لحساب المحيط -
اختبر في
main -
متقدم (الصعوبة ⭐⭐⭐): عرّف بنية
Date(السنة، الشهر، اليوم)، واكتب دالة للتحقق مما إذا كان التاريخ صالحاً (مثلاً 2024-02-29 صالح، 2023-02-29 غير صالح).
- البنية: تُعبّئ أنواعاً مختلفة من البيانات في وحدة واحدة
- الوصول للأعضاء يستخدم عامل النقطة .؛ المؤشرات تستخدم ->
- التهيئة: التهيئة الموحدة {} أو التعيين عضواً بعضو
- يمكن استخدام البنى كمعاملات دوال وقيم إرجاع
- مصفوفات البنى تدير سجلات متعددة
9. 🚀 الخطوات التالية
الآن بعد أن تعلمت البنى، لننتقل إلى المرحلة 4 (المؤشرات والمراجع) — الجزء الأصعب والأهم في C++، لكن إتقانه سيتيح لك كتابة كود أكثر كفاءة!