User Tools

Site Tools


cpp:exception

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revisionBoth sides next revision
cpp:exception [2019/05/06 07:16] – [Διαχείριση Εξαιρέσεων] gthanoscpp:exception [2019/05/06 07:17] – [Κληρονομικότητα εξαιρέσεων] gthanos
Line 204: Line 204:
 </WRAP> </WRAP>
  
-===== Κληρονομικότητα εξαιρέσεων ===== 
- 
-Ας υποθέσουμε ότι έχουμε τη σχέση κληρονομικότητας μεταξύ των κλάσεων **BaseException** και **DerivedException**, όπως παρακάτω: 
- 
-<code cpp BaseException.h> 
-using namespace std; 
- 
-class BaseException: public std::exception { 
-protected: 
-  int a; 
-public: 
-  BaseException(int a) { this->a = a; } 
-  const char* what() const throw() { 
-    //char s[64]; 
-    char *s = new char [64]; 
-    sprintf(s, "BaseException, a: %d\n", a); 
-    return s; 
-  } 
-}; 
-</code> 
- 
-<code cpp DerivedException.h> 
-#include "BaseException.h" 
-using namespace std; 
- 
-class DerivedException: public BaseException { 
-  int b; 
-public: 
-  DerivedException(int a, int b): BaseException(a) { this->b = b; } 
-  const char* what() const throw() { 
-    char *s = new char [64]; 
-    sprintf(s, "DerivedException, a: %d, b: %d\n", a, b); 
-    return s; 
-  } 
-}; 
-</code> 
- 
-<code cpp ExceptionUse.cpp> 
-#include <iostream> 
-#include "DerivedException.h" 
-using namespace std; 
- 
-int main() { 
-  try { 
-    int option; 
-    cout << "Enter option (1-2): "; 
-    cin >> option; 
-    BaseException bex(-2); 
-    DerivedException dex(4,5); 
-    switch(option) { 
-      case 1: 
-        throw bex; 
-        break; 
-      case 2: 
-        throw dex; 
-        break; 
-    } 
-  } catch(BaseException ex) { 
-    cout << ex.what(); 
-  } catch(DerivedException ex) { 
-    cout << ex.what(); 
-  } 
-  return 0; 
-} 
-</code> 
- 
-O παραπάνω κώδικας παράγει το παρακάτω //warning// κατά τη μεταγλώττιση: 
-<code> 
-ExceptionUse.cpp:22:5: warning: exception of type ‘DerivedException’ will be caught 
-   } catch(DerivedException &ex) { 
-     ^ 
-ExceptionUse.cpp:20:5: warning:    by earlier handler for ‘BaseException’ 
-   } catch(BaseException &ex) { 
-     ^ 
-</code> 
- 
-το οποίο εν συντομία λέει ότι ένα exception τύπου //DerivedException// θα "πιαστεί" από το 1ο //catch block// και το 2ο //catch block// δεν θα λειτουργήσει ποτέ. Το παραπάνω είναι λογικό διότι ένα αντικείμενο της κλάσης //DerivedException// είναι και //BaseException// με βάση τις αρχές της κληρονομικότητας. 
- 
-Εκτελέστε όμως τον παραπάνω κώδικα (παρά το warning) δίνοντας ορίσμα τους αριθμούς 1 και 2. Το αποτέλεσμα είναι το εξής: 
-<code> 
-gthanos@gthanos-DESKTOP:~/Downloads/C++$ ./ExceptionUse  
-Enter option (1-2): 1 
-BaseException, a: -2 
-gthanos@gthanos-DESKTOP:~/Downloads/C++$ ./ExceptionUse  
-Enter option (1-2): 2 
-BaseException, a: 4 
-</code> 
- 
-Παρατηρήστε ότι ενώ στην 2η περίπτωση παράγεται ένα //DerivedException// το αντικείμενο που τελικά λαμβάνουμε είναι τύπου //BaseException//. Εδώ θα πρέπει να τονίσουμε ότι η συνάρτηση //what()// είναι //virtual// πράγμα που σημαίνει ότι θα πρέπει να καλείται η κατάλληλη έκδοση της συνάρτησης με βάση τον τύπο του αντικειμένου για το οποίο καλείται, ανεξάρτητα από τον τύπο της η οποία δείχνει στο αντικείμενο (δες [[cpp:polymorphism|δυναμικό πολυμορφισμό]]). 
- 
-Η απάντηση στο παραπάνω ερώτημα είναι ότι αν και παράγεται ένα αντικείμενο τύπου //DerivedException// αυτό γίνεται //catch// από το πρώτο //catch block//. Μέσα στο //catch block// το αρχικό αντικείμενο αντιγράφεται σε ένα άλλο αντικείμενο τύπου //BaseException//, διότι έχουμε κλήση με τιμή στο //catch block//. Πρακτικά αυτό σημαίνει ότι από το αρχικό αντικείμενο κρατάμε οτιδήποτε ανήκει στην κλάση //BaseException// και απορρίπτουμε το υπόλοιπο. 
- 
-Ο τρόπος για να δουλέψει σωστά ο παραπάνω κώδικας είναι μέσα στο //catch block// να μην περάσουμε το αντικείμενο γιατί δημιουργείται αντίγραφο, αλλά να περάσουμε μία αναφορά σε αυτό, όπως παρακάτω: 
- 
-<code cpp ExceptionUse.cpp> 
-#include <iostream> 
-#include "DerivedException.h" 
-using namespace std; 
- 
-int main() { 
-  try { 
-    int option; 
-    cout << "Enter option (1-2): "; 
-    cin >> option; 
-    BaseException bex(-2); 
-    DerivedException dex(4,5); 
-    switch(option) { 
-      case 1: 
-        throw bex; 
-        break; 
-      case 2: 
-        throw dex; 
-        break; 
-    } 
-  } catch(BaseException &ex) { 
-    cout << ex.what(); 
-  } catch(DerivedException &ex) { 
-    cout << ex.what(); 
-  } 
-  return 0; 
-} 
-</code> 
- 
-Πλέον το αποτέλεσμα της εκτέλεσης είναι το αναμενόμενο 
-<code> 
-gthanos@gthanos-DESKTOP:~/Downloads/C++$ ./ExceptionUse  
-Enter option (1-2): 1 
-BaseException, a: -2 
-gthanos@gthanos-DESKTOP:~/Downloads/C++$ ./ExceptionUse  
-Enter option (1-2): 2 
-DerivedException, a: 4, b: 5 
-</code> 
- 
-<WRAP tip 80% center round> 
-Το πιάσιμο μιας εξαίρεσης με χρήση αναφοράς για αντικείμενα σύνθετου τύπου (όχι char, int, long, double κλπ), διότι //α)// αποφεύγουμε την αντιγραφή του αντικειμένου μέσα στο //catch block// (πιο γρήγορος κώδικας) και //β)// αποφεύγουμε την "αποκοπή" μέρους του αντικειμένου της εξαίρεσης λόγω του χειρισμού της από ένα //catch block// βασικότερου τύπου από τον τύπο του αντικειμένου της εξαίρεσης. 
-</WRAP> 
- 
-<WRAP tip 80% center round> 
-Είναι προφανές ότι η σειρά των //catch blocks// θα έπρεπε να είναι η αντίστροφη (πρώτα το //catch block// για την αναφορά τύπου //DerivedException// και στη συνέχεια το //catch block// για την αναφορά τύπου //BasedException//. Ο λόγος είναι ότι εάν παραμείνει η σειρά των //catch blocks// ως έχει το 2o catch block δεν εκτελείται ποτέ. 
-</WRAP> 
  
 ===== Stack Unwinding ===== ===== Stack Unwinding =====
cpp/exception.txt · Last modified: 2023/05/15 14:01 by gthanos