محتويات الدورة

C++ / الأساسي / الدرس 6

الأصناف والخصائص الثابتة والتركيب

ابنِ نوع قيمة صغيرًا يبدأ صالحًا، ويعرض عمليات واضحة، ويحافظ على اتساق الحالة المرتبطة أثناء الإنشاء والاستخدام.

وقت القراءة التقريبي: 4 دقيقةتاريخ مراجعة المحتوى
في هذه الصفحة

أهداف الدرس

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

تعريف معنى الكائن الصالح

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

إنشاء الأعضاء بحالة صالحة

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

cpp الفحص قبل تغيير المخزون
#include <iostream>
class Stock {
    int quantity_{10};
public:
    bool withdraw(int amount) {
        if (amount < 0 || amount > quantity_) { return false; }
        quantity_ -= amount;
        return true;
    }
    int quantity() const { return quantity_; }
};
int main() {
    Stock stock;
    std::cout << std::boolalpha << stock.withdraw(4) << " ";
    std::cout << stock.withdraw(8) << " " << stock.quantity() << "\n";
}
الناتج المتوقع
true false 6

تُسحب أربع وحدات من عشر. يتجاوز الطلب التالي الست المتبقية فيعيد false ويترك ست وحدات. القيمة الابتدائية المختارة عشرة.

التمييز بين المراقبة والتعديل

يمكن استدعاء الدالة العضو const على كائن ثابت، ولا تستطيع عادة تعديل أعضائه العادية. وتعبّر عن عملية مراقبة مثل quantity أو label. هذا قيد وصول أثناء الترجمة وليس ضمانًا لسلامة الخيوط؛ فالأعضاء mutable والكائنات الخارجية المشار إليها تحتاج إلى تحليل مستقل. أعد القيم الصغيرة بالقيمة. تعرّض إعادة مرجع إلى سلسلة داخلية اعتمادًا على العمر والإبطال، لذلك قد يفضّل إرجاع سلسلة مملوكة عند واجهة بسيطة حتى مع الحاجة إلى نسخة.

ترك إدارة الموارد للأعضاء

يعني التركيب أن يحتوي الصنف كائنات تنفّذ أجزاء من سلوكه. يستطيع Team احتواء std::string وstd::vector<std::string> بدل مؤشرات خام مالكة. تتبع عمليات الإنشاء والنسخ والإتلاف الأعضاء تلقائيًا، وهو أساس قاعدة الصفر. في البرنامج الثاني يقبل معامل بالقيمة اسم عضو مملوكًا، وينقل تمرير ذلك المعامل إلى المتجه تخزينه المتاح عندما يناسب. لا يحتفظ الفريق بمرجع إلى سلسلة المستدعي ولا يحتاج إلى مدمّر مكتوب يدويًا.

cpp صنف مركّب من أعضاء قياسية مالكة
#include <iostream>
#include <string>
#include <utility>
#include <vector>
class Team {
    std::string name_;
    std::vector<std::string> members_;
public:
    explicit Team(std::string name) : name_(std::move(name)) {}
    void add(std::string member) { members_.push_back(std::move(member)); }
    std::string label() const { return name_ + ": " + std::to_string(members_.size()); }
};
int main() {
    Team team{"North"};
    team.add("Mira");
    team.add("Omar");
    std::cout << team.label() << "\n";
}
الناتج المتوقع
North: 2

يملك الفريق اسمه واسمي عضوين، ويحرر مدمّره المولّد موارد المتجه والسلسلة.

اختبار العمليات كانتقالات حالة

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

الأخطاء الشائعة وإصلاحها

سحب يجعل المخزون سالبًا.

لماذا يحدث؟
تطرح العملية قبل فحص الطلب.
كيف تصلحه؟
ارفض الكميات السالبة والمفرطة قبل التعديل.
كيف تتجنب تكراره؟
راجع كل انتقال عام وفق الخاصية الثابتة.

قيم الأعضاء تعتمد على ترتيب تهيئة مضلل.

لماذا يحدث؟
تتبع التهيئة ترتيب التصريح بدلًا منه.
كيف تصلحه؟
صرّح بالاعتمادات أولًا وطابق ترتيب القائمة معها.
كيف تتجنب تكراره؟
فعّل تحذيرات الترتيب وتجنب التهيئة الدائرية.

مدمّر صنف يكرر تنظيف المكتبة القياسي.

لماذا يحدث؟
عوملت الحاويات المالكة كمؤشرات غير مدارة.
كيف تصلحه؟
دع أعضاء string وvector تتلف نفسها.
كيف تتجنب تكراره؟
فضّل قاعدة الصفر لأصناف القيم العادية.

اختبر فهمك

1. باستخدام Stock توقّع سحب صفر وسالب اثنين وعشرة من كائن جديد، مع القيم المعادة والكميات النهائية.

اعرض الحل المشروح

يحوي Stock جديد عشر وحدات. يعيد سحب الصفر true ويترك عشرة. ويعيد سحب سالب اثنين false ويترك عشرة. ثم يعيد سحب عشرة true ويترك صفرًا. تُنفّذ الطلبات بالتسلسل ولا تغيّر المرفوضة الكمية. أضف سحب واحد بعد ذلك لتتأكد أنه يعيد false وتبقى الكمية صفرًا.

2. صحّح تصميمًا يخزّن فيه Team مرجع const std::string& لاسم فريق مؤقت يقدّمه المستدعي، واشرح الملكية والأعضاء الخاصة المولدة.

اعرض الحل المشروح

خزّن std::string name_ بالقيمة كما في المثال. يستطيع الوسيط المؤقت حينها تهيئة تخزين مملوك يطابق عمر Team. ينسخ الناسخ المولّد قيمتي السلسلة والمتجه، ويحررهما المدمّر المولّد. أما العضو المرجعي فيبقي اعتماد الاستعارة وقد يتدلى بعد موت المؤقت؛ ونسخ المرجع لا ينشئ ملكية.

أهم ما تعلمته

  • أنشئ كائنات صالحة وحافظ على خصائصها الثابتة.
  • فضّل عمليات المسألة على ضبط الحقول بلا قيود.
  • ركّب أعضاء مالكة بالقيمة واستخدم قاعدة الصفر.

المراجع الرسمية