2013-04-24 8 views
20

तो मेरे पास अपवादों से निपटने और उनके वर्तमान पता पुस्तिका कार्यक्रम में उनका उपयोग करने वाला एक आगामी असाइनमेंट है जो अधिकांश होमवर्क केंद्रित है। मैंने अपवादों और पूरे प्रयास को पकड़ने की कोशिश की, और एक क्लास डिज़ाइन का उपयोग करने का फैसला किया, जो मुझे अंततः कुछ हफ्तों में मेरे असाइनमेंट के लिए करना होगा। मेरे पास ऐसा कोड है जो अपवाद को ठीक से जांचता है, लेकिन जो मैं जानना चाहता हूं, वह है कि अगर मेरा त्रुटि संदेश फ़ंक्शन मानकीकृत करने का कोई तरीका है, (यानी मेरा क्या() कॉल):अपवाद कैसे बनाएं?

यहां मेरा कोड है:

#include <iostream> 
#include <exception> 
using namespace std; 


class testException: public exception 
{ 
public: 
    virtual const char* what() const throw() // my call to the std exception class function (doesn't nessasarily have to be virtual). 
    { 
    return "You can't divide by zero! Error code number 0, restarting the calculator..."; // my error message 
    } 

    void noZero(); 

}myex; //<-this is just a lazy way to create an object 



int main() 
{ 
void noZero(); 
int a, b; 

cout << endl; 

cout << "Enter a number to be divided " << endl; 

cout << endl; 

cin >> a; 

cout << endl; 

cout << "You entered " << a << " , Now give me a number to divide by " << endl; 

cin >> b; 

try 
{  
    myex.noZero(b); // trys my exception from my class to see if there is an issue 
} 
catch(testException &te) // if the error is true, then this calls up the eror message and restarts the progrm from the start. 
{ 
    cout << te.what() << endl; 
    return main(); 
} 

cout <<endl; 

cout << "The two numbers divided are " << (a/b) << endl; // if no errors are found, then the calculation is performed and the program exits. 

return 0; 

} 

    void testException::noZero(int &b) //my function that tests what I want to check 
    { 
    if(b == 0) throw myex; // only need to see if the problem exists, if it does, I throw my exception object, if it doesn't I just move onto the regular code. 
    } 

मैं क्या करने में सक्षम होना चाहता हूं, ऐसा इसलिए है कि मेरा() फ़ंक्शन किस प्रकार की त्रुटि पर कॉल किया जा रहा है, इस पर निर्भर करता है। तो उदाहरण के लिए, अगर मैं एक त्रुटि को बुला रहा था जो शीर्ष संख्या को देखता था, (ए), यह देखने के लिए कि यह शून्य था या नहीं, और यदि यह था, तो यह संदेश कहने के लिए सेट करेगा कि "आपके पास नहीं हो सकता शून्य का एक अंशक ", लेकिन अभी भी() फ़ंक्शन के अंदर होना चाहिए। यहाँ एक उदाहरण है:

virtual const char* what() const throw() 
    if(myex == 1) 
    { 
     return "You can't have a 0 for the numerator! Error code # 1 " 
    } 
    else 

    return "You can't divide by zero! Error code number 0, restarting the calculator..."; // my error message 
    } 

यह स्पष्ट रूप से काम नहीं होगा, लेकिन वहां यह तो मैं प्रत्येक त्रुटि संदेश के लिए एक अलग समारोह लिख नहीं कर रहा हूँ बनाने के लिए एक तरीका है?

+9

एक शुरुआत के लिए की तरह लंबाई त्रुटि के लिए अपने स्वयं के अपवाद वर्ग बना सकते हैं कानूनी नहीं है। – jogojapan

+0

'नोज़रो' को 'testException' के अंदर कोई सदस्य नहीं होना चाहिए (या नहीं होना चाहिए)। इसे बाहर ले जाएं! – SuperSaiyan

+3

विचार आमतौर पर है कि आप प्रत्येक प्रकार के अपवाद के लिए एक अलग वर्ग लागू करते हैं। उनमें से प्रत्येक 'what()' फ़ंक्शन को अलग-अलग तरीके से ओवरराइड करता है, और आप स्ट्रिंग में टाइप-संबंधित जानकारी को शामिल करने के लिए स्पष्ट रूप से स्वतंत्र हैं। – jogojapan

उत्तर

35

आपके कोड में कई गलतफहमीएं हैं। संक्षिप्त उत्तर हाँ है, आप जो कुछ भी चाहते हैं उसे वापस करने के लिए आप what() बदल सकते हैं। लेकिन चलो कदम से कदम जाओ।

#include <iostream> 
#include <exception> 
#include <stdexcept> 
#include <sstream> 
using namespace std; 


class DivideByZeroException: public runtime_error { 
public: 

    DivideByZeroException(int x, int y) 
    : runtime_error("division by zero"), numerator(x), denominator(y) 
    {} 

    virtual const char* what() const throw() 
    { 
    cnvt.str(""); 

    cnvt << runtime_error::what() << ": " << getNumerator() 
     << "/" << getDenominator(); 

    return cnvt.str().c_str(); 
    } 

    int getNumerator() const 
    { return numerator; } 

    int getDenominator() const 
    { return denominator; } 

    template<typename T> 
    static T divide(const T& n1, const T& n2) 
    { 
     if (n2 == T(0)) { 
      throw DivideByZeroException(n1, n2); 
     } 

     return (n1/n2); 
    } 

private: 
    int numerator; 
    int denominator; 

    static ostringstream cnvt; 
}; 

ostringstream DivideByZeroException::cnvt; 

पहले स्थान पर, runtime_error, exception से ली गई है, से प्राप्त की सलाह अपवाद वर्ग है। यह stdexcept शीर्षलेख में घोषित किया गया है। आपको केवल what() विधि में वापस आने वाले संदेश के साथ अपने कन्स्ट्रक्टर को प्रारंभ करना होगा।

दूसरा, आपको उचित रूप से अपनी कक्षाओं का नाम देना चाहिए। मैं समझता हूं कि यह सिर्फ एक परीक्षण है, लेकिन एक वर्णनात्मक नाम हमेशा आपके कोड को पढ़ने और समझने में मदद करेगा।

जैसा कि आप देख सकते हैं, मैंने अपवाद को उजागर करने के लिए संख्याओं को स्वीकार करने के लिए कन्स्ट्रक्टर को बदल दिया है। आपने अपवाद में परीक्षण किया ... अच्छा, मैंने इसका सम्मान किया है, लेकिन एक स्थिर कार्य के रूप में जिसे बाहर से बुलाया जा सकता है।

और अंत में, what() विधि। चूंकि हम दो संख्याओं को विभाजित कर रहे हैं, इसलिए यह दिखाने के लिए अच्छा होगा कि दो संख्याएं जो अपवाद को उकसाती हैं। इसे प्राप्त करने का एकमात्र तरीका ostringstream का उपयोग है। यहां हम इसे स्थिर बनाते हैं इसलिए एक स्टैक ऑब्जेक्ट में पॉइंटर लौटने की कोई समस्या नहीं है (यानी, cnvt होने पर स्थानीय चर अपरिभाषित व्यवहार पेश करेगा)।

int main() 
{ 
int a, b, result; 

cout << endl; 

cout << "Enter a number to be divided " << endl; 

cout << endl; 

cin >> a; 

cout << endl; 

cout << "You entered " << a << " , Now give me a number to divide by " << endl; 

cin >> b; 

try 
{  
     result = DivideByZeroException::divide(a, b); 

    cout << "\nThe two numbers divided are " << result << endl; 
} 
catch(const DivideByZeroException &e) 
{ 
    cout << e.what() << endl; 
} 

return 0; 

} 

आप देख सकते हैं, मैं अपने return main() अनुदेश निकाल दिया है:

कार्यक्रम के बाकी कम या ज्यादा के रूप में आप इसे अपने प्रश्न में सूचीबद्ध है। यह समझ में नहीं आता है, क्योंकि आप main() को पुनरावर्ती रूप से कॉल नहीं कर सकते हैं। इसके अलावा, इसका उद्देश्य एक गलती है: आप अपवाद को उकसाए जाने वाले ऑपरेशन को पुनः प्रयास करने की अपेक्षा करेंगे, लेकिन यह संभव नहीं है, क्योंकि अपवाद पुनर्वित्त नहीं हैं।हालांकि, आप स्रोत कोड एक छोटा सा, एक ही प्रभाव को प्राप्त करने बदल सकते हैं:

int main() 
{ 
int a, b, result; 
bool error; 

do { 
    error = false; 

    cout << endl; 

    cout << "Enter a number to be divided " << endl; 

    cout << endl; 

    cin >> a; 

    cout << endl; 

    cout << "You entered " << a << " , Now give me a number to divide by " << endl; 

    cin >> b; 

    try 
    {  
     result = DivideByZeroException::divide(a, b); // trys my exception from my class to see if there is an issue 

     cout << "\nThe two numbers divided are " << result << endl; 
    } 
    catch(const DivideByZeroException &e) // if the error is true, then this calls up the eror message and restarts the progrm from the start. 
    { 
     cout << e.what() << endl; 
     error = true; 
    } 
} while(error); 

return 0; 

} 

आप देख सकते हैं, जब तक एक "उचित" विभाजन दर्ज किया गया है एक त्रुटि के मामले में निष्पादन इस प्रकार है।

उम्मीद है कि इससे मदद मिलती है।

+0

वास्तव में कोई अपवाद वर्ग नहीं है "इसे प्राप्त करने की सलाह दी गई है"। यदि यह आपको कोड में मदद करता है तो अपने स्वयं के अपवाद वर्गों का उपयोग करना बिल्कुल ठीक है। बस जागरूक रहें कि 'std' में सबकुछ' 'से अपवाद फेंकता है। – rubenvb

+2

यह वास्तव में अनिवार्य नहीं है, लेकिन यह आसान है (रनटाइम आतंक मुख्य त्रुटि संदेश सेट करने के लिए स्ट्रिंग के लिए एक कन्स्ट्रक्टर प्रदान करता है) और अपवाद से सीधे प्राप्त करने की तुलना में संभावित रूप से अधिक महत्वपूर्ण है (क्योंकि आप "सुझाए गए" मानक अपवाद पदानुक्रम का पालन कर रहे हैं) । इसके अलावा, हाँ, अगर आप ऐसा करना पसंद करते हैं तो आप भी int को फेंक सकते हैं। – Baltasarq

+0

वाह। ठीक है, यह बहुत अच्छा है, धन्यवाद। माना जाता है कि यह सब कुछ समझने में मुझे कुछ समय लगेगा, लेकिन यह मेरा अभ्यास है। मुझे लगता है कि बेस क्लास अपवाद असाइनमेंट की आवश्यकता है, लेकिन मैं पूछूंगा कि क्या हम इसके स्थान पर runtime_error का उपयोग कर सकते हैं। इस के बाद हमारे असाइनमेंट टेम्पलेट्स को कवर करता है, इसलिए इसमें इसका उपयोग भी अच्छा अभ्यास होना चाहिए! इनपुट के लिए धन्यवाद, इससे यह समझने में बहुत मदद मिलनी चाहिए कि अपवाद कैसे काम करते हैं। –

2
class zeroNumerator: public std::exception 
{ 
    const char* what() const throw() { return "Numerator can't be 0.\n"; } 
}; 

//... 

try 
{ 
    myex.noZero(b); // trys my exception from my class to see if there is an issue 
    if(myex==1) 
    { 
    throw zeroNumerator(); // This would be a class that you create saying that you can't have 0 on the numerator 
    } 

} 
catch(testException &te) 
{ 
    cout << te.what() << endl; 
    return main(); 
} 

तुम हमेशा std :: अपवाद का उपयोग करना चाहिए & ई। तो

catch(std::exception & e) 
{ 
    cout<<e.what(); 
} 
+0

अगर मैं का उपयोग 'पकड़ (std :: अपवाद और ई)' तो मैं उत्पादन –

+2

नहीं .क्या डिफ़ॉल्ट के साथ फंस किया जाएगा क्योंकि आप एक वर्ग वर्ग zeroNumerator बनाना होगा: सार्वजनिक std :: अपवाद { \t स्थिरांक चार * क्या() कॉन्स फेंक() {वापसी "न्यूमेरेटर 0 नहीं हो सकता" }; –

+1

यह शून्य संख्या को पकड़ लेगा क्योंकि यह वही प्रयास है और ब्लॉक को पकड़ता है ... यह जानता है कि क्या पकड़ना है ... अगर आप मुझ पर भरोसा नहीं करते हैं तो इसे आजमाएं –

0

आपको कक्षाओं का पदानुक्रम माना जाना चाहिए।

स्ट्रिंग को स्थानांतरित करने के लिए अपवादों का उपयोग करने का प्रयास करते समय यह स्पष्ट नहीं हो सकता है, लेकिन असाधारण स्थितियों के उन्नत संचालन के लिए अपवादों का उपयोग करने का वास्तविक इरादा होना चाहिए। सी ++ रनटाइम पर्यावरण के हुड के तहत बहुत सी चीजें की जा रही हैं, जबकि 'फेंक' से 'कैच' से यात्रा करते समय कॉल स्टैक अवांछित है।

वर्गों का एक उदाहरण हो सकता है:

class DivisionError : public std::exception { 
public: 
    DevisionError(const int numerator, const int divider) 
     :numerator(numerator) 
     , divider(divider) 
    { 
    } 
    virtual const char* what() const noexcept { 
     // ... 
    } 
    int GetNumerator() const { return numerator; } 
    int GetDevider() const { return divider; } 
private: 
    const int numerator; 
    const int divider; 
}; 


class BadNumeratorError : public DivisionError { 
public: 
    BadNumeratorError(int numerator, int divider) 
     : DivisionError(numerator, divider) 
    { 
    } 
    virtual const char* what() const noexcept { 
    { 
     // ... 
    } 
}; 


class ZeroDeviderError : public DivisionError { 
public: 
    ZeroDeviderError(int numerator, int divider) 
     : DivisionError(numerator, divider) 
    { 
    } 
    virtual const char* what() const noexcept { 
    { 
     // .... 
    } 
}; 
  • त्रुटियों के लिए विभिन्न वर्गों प्रदान करना, आप डेवलपर्स विशेष तरीकों से अलग त्रुटियों (सिर्फ एक त्रुटि संदेश प्रदर्शित नहीं)
  • को संभालने के लिए एक मौका देने
  • त्रुटि के प्रकारों के लिए बेस क्लास प्रदान करना, डेवलपर्स को अधिक लचीला होने की अनुमति देता है - जितना आवश्यक हो उतना विशिष्ट हो।

कुछ मामलों में, वे विशिष्ट

} catch (const ZeroDividerError & ex) { 
// ... 
} catch (const DivisionError & ex) { 
दूसरों में

होने की जरूरत है, ऐसा नहीं

} catch (const DivisionError & ex) { 

कुछ अतिरिक्त जानकारी के लिए के रूप में,

  • आप नहीं करना चाहिए आपके द्वारा किए गए तरीके से फेंकने से पहले अपने अपवादों की वस्तुएं बनाएं। आपकी मंशा के बावजूद, यह केवल बेकार है - वैसे भी, आप पकड़ अनुभाग में ऑब्जेक्ट की एक प्रति के साथ काम कर रहे हैं (संदर्भ के माध्यम से पहुंच से भ्रमित न हों)
  • एक कॉन्स्ट संदर्भ का उपयोग करना एक अच्छी शैली होगी catch (const testException &te) जब तक आप वास्तव में नहीं एक गैर-निरंतर वस्तु की आवश्यकता है।
2

आप रिकर्सिवली बुला `main`, इस

class MyException : public std::length_error{ 
public: 
    MyException(const int &n):std::length_error(to_string(n)){} 
}; 
संबंधित मुद्दे