الارتباطات المهيكلة
جزء من قسم Object Oriented Programming في رحلة C++ على Coddy — الدرس 88 من 104.
تسمح لك الارتباطات المهيكلة (Structured bindings)، التي تم تقديمها في C++17، بتفكيك قيم متعددة من المصفوفات (arrays)، أو الأزواج (pairs)، أو الصفوف (tuples)، أو الهياكل (structs) إلى متغيرات مسماة فردية في تصريح واحد. وهذا يجعل الكود أكثر نظافة وقابلية للقراءة عند التعامل مع البيانات المركبة.
يستخدم بناء الجملة auto مع أقواس مربعة تحتوي على أسماء المتغيرات الجديدة:
#include <iostream>
#include <map>
#include <tuple>
int main() {
// فك حزمة زوج (pair)
std::pair<std::string, int> person{"Alice", 25};
auto [name, age] = person;
std::cout << name << " is " << age << "\n";
// فك حزمة صف (tuple)
std::tuple<int, double, char> data{42, 3.14, 'X'};
auto [num, pi, letter] = data;
// فك الحزم في حلقات for المبنية على النطاق
std::map<std::string, int> scores{{"Bob", 90}, {"Carol", 85}};
for (const auto& [student, score] : scores) {
std::cout << student << ": " << score << "\n";
}
}تعمل الارتباطات المهيكلة (Structured bindings) أيضاً مع المصفوفات والبنيات المخصصة (custom structs) التي تحتوي على أعضاء عامة:
struct Point {
double x;
double y;
};
Point getOrigin() { return {0.0, 0.0}; }
int main() {
auto [x, y] = getOrigin();
int arr[3] = {1, 2, 3};
auto [a, b, c] = arr;
}يمكنك استخدام auto& أو const auto& للربط بالمرجع، مما يتجنب عمليات النسخ ويسمح بتعديل القيم الأصلية عند الحاجة. هذه الميزة مفيدة بشكل خاص عند التكرار عبر حاويات STL أو التعامل مع الدوال التي تُرجع قيمًا متعددة.
التحدي
سهللنقم ببناء محلل لدرجات الطلاب يستعرض قوة الربط الهيكلي (structured bindings). ستقوم بإنشاء نظام يعالج سجلات الطلاب وبيانات الدورات التدريبية، باستخدام الربط الهيكلي لفك حزم الأزواج (pairs)، والصفوف (tuples)، والهياكل (structs) بأناقة في جميع أنحاء الكود الخاص بك.
ستقوم بتنظيم الكود الخاص بك عبر ثلاثة ملفات:
Student.h: قم بتعريف هيكلStudentمع أعضاء عامة لاسم الطالب (std::string)، والمعرف (int)، والمعدل التراكمي (double). قم أيضًا بإنشاء دالة تسمىcreateStudentتأخذ الاسم، والمعرف، والمعدل التراكمي، وتعيد هيكلStudent.GradeUtils.h: قم بإنشاء دوال مساعدة لمعالجة الدرجات.قم بتعريف دالة
getGradeInfoتأخذ درجة رقمية (عدد صحيح) وتعيدstd::tupleيحتوي على ثلاث قيم: التقدير الحرفي (std::string)، ونقاط التقدير (double)، وما إذا كانت درجة نجاح (bool). استخدم مقياس الدرجات هذا:- 90+ : "A", 4.0, true
- 80-89: "B", 3.0, true
- 70-79: "C", 2.0, true
- 60-69: "D", 1.0, true
- أقل من 60: "F", 0.0, false
قم أيضًا بتعريف دالة
makeScorePairتأخذ اسم الدورة (std::string) والدرجة (int)، وتعيدstd::pairمن تلك القيم.main.cpp: اقرأ أربعة مدخلات:- اسم الطالب (string)
- معرف الطالب (integer)
- اسم الدورة (string)
- الدرجة (integer)
استخدم الربط الهيكلي في جميع أنحاء دالتك الرئيسية:
- استدعِ
createStudentبالاسم، والمعرف، ومعدل تراكمي مؤقت قيمته 0.0. استخدم الربط الهيكلي لفك الهيكل المعاد إلى متغيرات فردية، ثم اطبع:Student: [name] (ID: [id]) - استدعِ
makeScorePairباسم الدورة والدرجة. استخدم الربط الهيكلي لفك الزوج، ثم اطبع:Course: [course], Score: [score] - استدعِ
getGradeInfoبالدرجة. استخدم الربط الهيكلي لفك جميع عناصر الصف الثلاثة، ثم اطبع:(اطبع "yes" إذا كان النجاح true، و "no" إذا كان false)Grade: [letter] Points: [points] Passing: [yes/no]
على سبيل المثال، مع المدخلات Alice، و 1001، و Math، و 85:
Student: Alice (ID: 1001)
Course: Math, Score: 85
Grade: B
Points: 3
Passing: yesمع المدخلات Bob، و 2002، و Physics، و 55:
Student: Bob (ID: 2002)
Course: Physics, Score: 55
Grade: F
Points: 0
Passing: noتذكر تضمين <tuple> و <utility> حيثما لزم الأمر. الفكرة الأساسية هي كيف يسمح لك الربط الهيكلي بفك الأنواع المركبة — الأزواج، والصفوف، والهياكل — إلى متغيرات مسماة في إعلان واحد مقروء.
ورقة مرجعية
تسمح الروابط المهيكلة (Structured bindings) في (C++17) بتفكيك قيم متعددة من المصفوفات، أو الأزواج (pairs)، أو المجموعات (tuples)، أو الهياكل (structs) إلى متغيرات مسماة فردية في تصريح واحد.
يستخدم بناء الجملة الأساسي auto مع الأقواس المربعة:
auto [var1, var2, ...] = composite_object;تفكيك std::pair:
std::pair<std::string, int> person{"Alice", 25};
auto [name, age] = person;تفكيك std::tuple:
std::tuple<int, double, char> data{42, 3.14, 'X'};
auto [num, pi, letter] = data;استخدام الروابط المهيكلة في حلقات for المبنية على النطاق (range-based for loops) مع الحاويات مثل std::map:
std::map<std::string, int> scores{{"Bob", 90}, {"Carol", 85}};
for (const auto& [student, score] : scores) {
std::cout << student << ": " << score << "\n";
}تفكيك الهياكل (structs) ذات الأعضاء العامة (public members):
struct Point {
double x;
double y;
};
Point getOrigin() { return {0.0, 0.0}; }
auto [x, y] = getOrigin();تفكيك المصفوفات (arrays):
int arr[3] = {1, 2, 3};
auto [a, b, c] = arr;استخدم auto& أو const auto& للربط عن طريق المرجع (reference)، مما يتجنب النسخ ويسمح بتعديل القيم الأصلية:
auto& [x, y] = point; // يمكن تعديل الأصل
const auto& [name, age] = person; // مرجع للقراءة فقطجرّب بنفسك
#include <iostream>
#include <string>
#include "Student.h"
#include "GradeUtils.h"
int main() {
// قراءة المدخلات
std::string studentName;
int studentId;
std::string courseName;
int score;
std::cin >> studentName;
std::cin >> studentId;
std::cin >> courseName;
std::cin >> score;
// TODO: استدعِ createStudent مع name و id و GPA مؤقت بقيمة 0.0
// استخدم structured bindings لفك الهيكل (struct): auto [name, id, gpa] = ...
// طباعة: Student: [name] (ID: [id])
// TODO: استدعِ makeScorePair مع course name و score
// استخدم structured bindings لفك الزوج (pair): auto [course, sc] = ...
// طباعة: Course: [course], Score: [score]
// TODO: استدعِ getGradeInfo مع score
// استخدم structured bindings لفك الصف (tuple): auto [letter, points, passing] = ...
// طباعة:
// Grade: [letter]
// Points: [points]
// Passing: [yes/no] (اطبع "yes" إذا كان passing هو true، و "no" إذا كان false)
return 0;
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
1أساسيات الـ OOP
الملفات الخارجيةبناء وتجميع (Compilation) لغة C++ملفات الـ Header وملفات الـ Sourceالـ Namespaces والـ Scopeمقدمة في الـ OOP في C++الـ Classes مقابل الـ Objectsالمؤشر 'this'الـ Methods (الدوال الأعضاء)الـ Attributes (بيانات الأعضاء)أساسيات الـ Ctors والـ Dtorsمراجعة - آلة حاسبة بسيطة4خصائص الـ Class
أعضاء الـ Instance مقابل الـ Staticدوال الـ Getters والـ Settersدوال الأعضاء الثابتة (Const)الكلمة المفتاحية Mutableالدوال والمتغيرات الساكنة (Static)الدوال والفئات الصديقة (Friend)مراجعة - مدير الحساب البنكي7الوراثة
الوراثة الأساسيةمستويات الوصول في الوراثةترتيب استدعاء الـ Ctor والـ Dtorإعادة تعريف الدوال (Method Overriding)الدوال الافتراضية والـ VTableالوراثة المتعددةالوراثة الافتراضيةمراجعة - هيكلية الموظفين10نظرة عامة على STL
نظرة عامة وفلسفة STLحاويات STLالـ Iteratorsخوارزميات STLالـ Functors وتعبيرات Lambdaمراجعة - تكرار الكلمات13أنماط التصميم - الجزء الأول
مقدمة في أنماط التصميمنمط Singletonنمط Factory و Abstract Factoryنمط Builderنمط Observerنمط Strategy2إدارة الذاكرة
ذاكرة Stack مقابل Heapالمؤشرات والمراجعالذاكرة الديناميكية (new/delete)المؤشرات الذكية في C++RAII في C++مراجعة - مدير المصفوفات الديناميكية5التغليف (Encapsulation)
محددات الوصول في C++محددات الوصول بشكل متعمقإخفاء المعلوماتStruct مقابل Classالأصناف المتداخلة والداخليةمراجعة - نظام سجلات الطلاب8تعدد الأشكال (Polymorphism)
تعدد الأشكال: وقت التجميع مقابل وقت التشغيلالتحميل الزائد للدوال (Function Overloading)مراجعة الدوال الافتراضية (Virtual Functions)الدوال الافتراضية البحتة (Pure Virtual Functions)الأصناف المجردة (Abstract Classes)تصميم الواجهات (Interface) في C++التحويل الديناميكي (Dynamic Casting) و RTTIملخص - حاسبة الأشكال11مفاهيم OOP المتقدمة
التركيب مقابل الوراثةالـ Mixins عبر CRTPنمط Pimplمحو النوع (Type Erasure)أصناف Enum والأنواع القويةمعالجة الاستثناءات في OOPتسلسلات الاستثناءات المخصصة14أنماط التصميم - الجزء الثاني
نمط الأمرنمط المحولنمط المزيننمط قالب الطريقةنمط الحالةنمط التركيبRAII كنمط3المنشئات والموادم
المنشئ الافتراضيالمنشئ ذو المعاملاتمنشئ النسخمنشئ النقلقوائم تهيئة المنشئالمنشئات المفوضةتعمق في الموادمقاعدة الثلاثة / الخمسة / الصفرمراجعة - فئة String6تحميل العوامل (Operator Overloading)
مقدمة في تحميل العواملتحميل العوامل الحسابيةتحميل عوامل المقارنةعوامل Streamتحميل عامل التعيينتحميل العوامل [] و ()عوامل تحويل النوعمراجعة - Matrix Class9القوالب
قوالب الدوالقوالب الأصنافتخصيص القوالبالقوالب المتغيرةأساسيات SFINAE و Type Traitsمراجعة - الحاويات العامة12ميزات C++ الحديثة
دلالات النقل و Rvaluesالتمرير المثاليتعبيرات Lambda بعمقstd::function و std::bindconstexpr و constevalالارتباطات المهيكلةoptional و variant و any