Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

تسلسلات الاستثناءات المخصصة

جزء من قسم البرمجة كائنية التوجه في رحلة C++ على Coddy. الدرس 82 من 104.

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

عادةً ما inherits class الاستثناء المخصصة من std::exception أو إحدى فئاتها المشتقة، وتتجاوز الطريقة what():

#include <exception>
#include <string>

class DatabaseException : public std::exception {
    std::string message;
public:
    DatabaseException(const std::string& msg) : message(msg) {}
    const char* what() const noexcept override { return message.c_str(); }
};

class ConnectionException : public DatabaseException {
public:
    ConnectionException(const std::string& host) 
        : DatabaseException("Failed to connect to: " + host) {}
};

class QueryException : public DatabaseException {
public:
    QueryException(const std::string& query) 
        : DatabaseException("Invalid query: " + query) {}
};

يتيح هذا التسلسل الهرمي لكتل catch معالجة الاستثناءات بمستويات مختلفة من التحديد:

try {
    // عمليات قاعدة البيانات...
    throw ConnectionException("localhost");
} catch (const ConnectionException& e) {
    std::cout << "Connection issue: " << e.what() << "\n";
} catch (const DatabaseException& e) {
    std::cout << "Database error: " << e.what() << "\n";
} catch (const std::exception& e) {
    std::cout << "General error: " << e.what() << "\n";
}

مُحدِّد noexcept في what() مهم - فهو يضمن أن الطريقة لن تُلقي استثناءً، وهذا مطلوب من واجهة الفئة الأساسية. رتّب كتل catch من الأكثر تحديدًا إلى الأكثر عمومية، إذ تستخدم C++ أول معالج مطابق.

challenge icon

التحدي

سهل

لنَبْنِ نظامًا لمعالجة الملفات باستخدام تسلسل هرمي مخصّص لـ exception يتعامل مع أنواع مختلفة من الأخطاء المتعلقة بالملفات. ستنشئ exceptions خاصة بالمجال ترث من base exception class، مما يتيح معالجة دقيقة للأخطاء على مستويات مختلفة من التحديد.

ستنظّم التعليمات البرمجية عبر ثلاثة ملفات:

  • FileExceptions.h: عرّف تسلسل exception الهرمي المخصّص لعمليات الملفات.

    أنشئ base FileException class يرث من std::exception. يجب أن يخزّن رسالة error ويتجاوز method what() باستخدام محدِّد noexcept.

    ثم أنشئ classَين مشتقَّين من exception:

    • FileNotFoundException: يأخذ filename وينشئ رسالة: File not found: [filename]
    • PermissionDeniedException: يأخذ filename وينشئ رسالة: Permission denied: [filename]

    يجب أن يستدعي كل class مشتق constructor الخاص بالـ parent مع الرسالة المناسبة.

  • FileProcessor.h: عرّف FileProcessor class يحاكي عمليات الملفات ويطرح exceptions المخصّصة.

    يجب أن يحتوي FileProcessor على method باسم openFile(const std::string& filename) تحاكي فتح ملف:

    • إذا كان filename يحتوي على missing، اطرح FileNotFoundException
    • إذا كان filename يحتوي على locked، اطرح PermissionDeniedException
    • خلاف ذلك، أعد string Successfully opened: [filename]
  • main.cpp: اقرأ filename واحدًا من الإدخال.

    أنشئ FileProcessor وحاول فتح الملف. استخدم try-catch block مع ترتيب handlers من الأكثر تحديدًا إلى الأكثر عمومية:

    1. التقط FileNotFoundException واطبع: File Error: [message]
    2. التقط PermissionDeniedException واطبع: Access Error: [message]
    3. التقط FileException واطبع: General File Error: [message]

    إذا لم يتم طرح exception، فاطبع رسالة النجاح التي يعيدها openFile().

على سبيل المثال، مع الإدخال report.txt:

Successfully opened: report.txt

مع الإدخال missing_data.csv:

File Error: File not found: missing_data.csv

مع الإدخال locked_config.ini:

Access Error: Permission denied: locked_config.ini

يوضح هذا التحدي كيف تتيح لك تسلسلات exception الهرمية المخصّصة معالجة الأخطاء على مستوى التفاصيل المناسب: التقاط exceptions محددة عندما تحتاج إلى معالجة دقيقة، أو التقاط base exception عندما تريد معالجة جميع أخطاء الملفات بشكل موحّد.

جرّب بنفسك

#include <iostream>
#include <string>
#include "FileExceptions.h"
#include "FileProcessor.h"

using namespace std;

int main() {
    string filename;
    cin >> filename;
    
    FileProcessor processor;
    
    // TODO: استخدم كتلة try-catch للتعامل مع الاستثناءات
    // رتّب المعالجات من الأكثر تحديدًا إلى الأكثر عمومية:
    // 1. التقط FileNotFoundException - اطبع: "File Error: [message]"
    // 2. التقط PermissionDeniedException - اطبع: "Access Error: [message]"
    // 3. التقط FileException - اطبع: "General File Error: [message]"
    // إذا لم يحدث استثناء، اطبع رسالة النجاح من openFile()
    
    try {
        // TODO: استدعِ processor.openFile() وتعامل مع النتيجة
        
    }
    // TODO: أضف كتل catch بالترتيب من الأكثر تحديدًا إلى الأكثر عمومية
    
    return 0;
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس البرمجة كائنية التوجه

تدرّب بنفسك: مترجم C++ عبر الإنترنت