היררכיות חריגות מותאמות אישית
חלק מהיחידה תכנות מונחה עצמים במסלול ה-C++ של Coddy. שיעור 82 מתוך 104.
בעוד שהספרייה הסטנדרטית מספקת מחלקות חריגה שימושיות כמו std::runtime_error, יישומים מהעולם האמיתי מפיקים לעיתים קרובות תועלת מיצירת היררכיות חריגות מותאמות אישית. באמצעות הגדרת מחלקות חריגה משלך שיורשות מחריגות סטנדרטיות, תוכל ליצור סוגי שגיאות ייעודיים לתחום, הנושאים הקשר נוסף ומאפשרים טיפול מדויק יותר בשגיאות.
מחלקת חריגות מותאמת אישית יורשת בדרך כלל מ־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++ משתמש במטפל הראשון שמתאים.
אתגר
קלבואו נבנה מערכת לעיבוד קבצים עם היררכיית חריגות מותאמת אישית שמטפלת בסוגים שונים של שגיאות הקשורות לקבצים. תיצרו חריגות ייעודיות לתחום שיורשות ממחלקת חריגה בסיסית, וכך יתאפשר טיפול מדויק בשגיאות ברמות שונות של פירוט.
תארגנו את הקוד שלכם בשלושה קבצים:
FileExceptions.h: הגדירו את היררכיית החריגות המותאמת אישית שלכם עבור פעולות קבצים.צרו מחלקת בסיס בשם
FileExceptionשיורשת מ-std::exception. עליה לשמור הודעת שגיאה ולדרוס את המתודהwhat()עם המצייןnoexcept.לאחר מכן, צרו שתי מחלקות חריגה נגזרות:
FileNotFoundException: מקבלת שם קובץ ויוצרת הודעה:File not found: [filename]PermissionDeniedException: מקבלת שם קובץ ויוצרת הודעה:Permission denied: [filename]
כל מחלקה נגזרת צריכה לקרוא לבנאי של מחלקת האב שלה עם ההודעה המתאימה.
FileProcessor.h: הגדירו מחלקתFileProcessorשמדמה פעולות על קבצים וזורקת את החריגות המותאמות אישית שלכם.במחלקת
FileProcessorצריכה להיות מתודה בשםopenFile(const std::string& filename)שמדמה פתיחת קובץ:- אם שם הקובץ מכיל את
missing, זרקוFileNotFoundException - אם שם הקובץ מכיל את
locked, זרקוPermissionDeniedException - אחרת, החזירו את המחרוזת
Successfully opened: [filename]
- אם שם הקובץ מכיל את
main.cpp: קראו שם קובץ יחיד מהקלט.צרו
FileProcessorונסו לפתוח את הקובץ. השתמשו בבלוק try-catch עם מטפלים המסודרים מהספציפי ביותר לכללי ביותר:- תפסו
FileNotFoundExceptionוהדפיסו:File Error: [message] - תפסו
PermissionDeniedExceptionוהדפיסו:Access Error: [message] - תפסו
FileExceptionוהדפיסו:General File Error: [message]
אם לא נזרקת חריגה, הדפיסו את הודעת ההצלחה שמוחזרת על ידי
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האתגר הזה מדגים כיצד היררכיות חריגות מותאמות אישית מאפשרות לכם לטפל בשגיאות ברמת הפירוט המתאימה: לתפוס חריגות ספציפיות כשנדרש טיפול מדויק, או לתפוס את חריגת הבסיס כשרוצים לטפל בכל שגיאות הקבצים באופן אחיד.
נסו בעצמכם
#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;
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1יסודות OOP
קבצים חיצונייםבנייה וקומפילציה של C++קובצי Header וקובצי מקורמרחבי שמות והיקףמבוא ל-OOP ב-C++מחלקות לעומת אובייקטיםמצביע thisמתודות (פונקציות איבר)תכונות (חברי נתונים)יסודות הבנאים וההורסיםסיכום – מחשבון פשוט4מאפייני מחלקה
חברי מופע לעומת חברים סטטייםגטרים וסטריםפונקציות איבר קבועותמילת המפתח mutableמתודות ומשתנים סטטייםפונקציות ומחלקות ידידותסיכום – מנהל חשבונות בנק7ירושה
ירושה בסיסיתרמות גישה בירושהסדר הקריאות לבנאי ולמפרקדריסת מתודותפונקציות וירטואליות ו־VTableירושה מרובהירושה וירטואליתסיכום – היררכיית עובדים2ניהול זיכרון
זיכרון Stack לעומת Heapמצביעים והפניותזיכרון דינמי (new/delete)מצביעים חכמים ב-C++RAII ב-C++סיכום – מנהל מערכים דינמיים5כימוס
מצייני גישה ב-C++מצייני גישה לעומקהסתרת מידעמבנה לעומת מחלקהמחלקות מקוננות ופנימיותסיכום – מערכת רשומות תלמידים8רב־צורתיות
רב־צורתיות בזמן קומפילציה לעומת בזמן ריצההעמסת פונקציותפונקציות וירטואליות — מבט נוסףפונקציות וירטואליות טהורותמחלקות מופשטותתכנון ממשקים ב־C++המרה דינמית ו־RTTIסיכום — מחשבון צורות11מושגי OOP מתקדמים
הרכבה לעומת הורשהMixins באמצעות CRTPאידיום Pimplמחיקת טיפוסיםמחלקות Enum וטיפוסיות חזקהטיפול בחריגות ב-OOPהיררכיות חריגות מותאמות אישית3בנאים והורסים
בנאי ברירת מחדלבנאי עם פרמטריםבנאי העתקהבנאי העברהרשימות אתחול בבנאיםבנאים מאציליםמעמיקים בנושא הורסיםכלל השלושה / החמישה / האפססיכום – מחלקת String6העמסת אופרטורים
מבוא להעמסת אופרטוריםהעמסת אופרטורים אריתמטייםהעמסת אופרטורי השוואהאופרטורי זרםהעמסת אופרטור השמההעמסת האופרטורים [] ו־()אופרטורים להמרת טיפוסיםסיכום – מחלקת Matrix9תבניות
תבניות פונקציהתבניות מחלקההתמחות תבניותתבניות ארגומנטים משתנותיסודות SFINAE ותכונות טיפוסיםסיכום – מכל גנריתרגלו בעצמכם: קומפיילר C++ אונליין