-1

this is v1 which results in errors

#include <iostream>
#include "exceptionHandlingV2.h"
using namespace std;
int main() {
    exceptionHandlingV2 ob(4,0);
    cout<<ob.divide();
    cout<<"\nbye";
    return 0;
}

#ifndef EXCEPTION_HANDLING_V2_EXCEPTIONHANDLINGV2_H
#define EXCEPTION_HANDLING_V2_EXCEPTIONHANDLINGV2_H
#include <iostream>
using namespace std;

class exceptionHandlingV2 {
private:
    int numerator;
    int denominator;
    string error;
public:
    exceptionHandlingV2();
    exceptionHandlingV2(int ,int);

    void setDenominator(int );
    void setNumerator(int );

    void readAgain ();
    void print_errors();

    double divide() const;
};
#endif //EXCEPTION_HANDLING_V2_EXCEPTIONHANDLINGV2_H

#include "exceptionHandlingV2.h"
exceptionHandlingV2::exceptionHandlingV2(){
    numerator=1;
    denominator=1;
}
exceptionHandlingV2::exceptionHandlingV2(int numerator,int denominator){
    setNumerator(numerator);
    try {
        setDenominator(denominator);
        error = "";
    }catch (const char * e){
        error = e;
        print_errors();
        readAgain();
    }
}

void exceptionHandlingV2::setDenominator(int denominator){
    if ( denominator == 0 ){
        throw "divided by zero\n";
    }

    (*this).denominator = denominator;
}

void exceptionHandlingV2::readAgain (){
    int temp;
    cout<<"enter denominator again other than 0\n";
    cin >> temp;
    exceptionHandlingV2 ( numerator,temp );
}
void exceptionHandlingV2::print_errors(){
    cout<<error;
}
void exceptionHandlingV2::setNumerator(int numerator){
    (*this).numerator = numerator;
}

double exceptionHandlingV2::divide() const{
    return (double)numerator/denominator;
}

this is v2 design which i stopped interacting with user in constructor

exceptionHandlingV2::exceptionHandlingV2(int numerator,int denominator){
    setNumerator(numerator);
    setDenominator( denominator );
}

void exceptionHandlingV2::setDenominator(int denominator){

    try
    {
        if ( denominator == 0 )
            throw "divided by zero\n";

        (*this).denominator = denominator;
        error = "";
    }
    catch (const char * e)
    {
        error = e;
        print_errors();
        readAgain();
    }

}

in v3 design I added a new function to handle exception inside the class itself

exceptionHandlingV4::exceptionHandlingV4(int numerator,int denominator){
    setNumerator(numerator);
    setDenominator( denominator );
}

void exceptionHandlingV4::setDenominator(int denominator){

    try {
        runtime_set_denominator_error ( denominator );

    }
    catch ( const char *e )
    {
        error = e;
        print_errors();
        readAgain();
    }
}

void exceptionHandlingV4 :: runtime_set_denominator_error  ( int denominator ){

    if ( !denominator )
        throw "divided by zero \n";
  
    (*this).denominator = denominator;
    error = "";
}

I made a v4 design to stop handling exception in class , rather doing it in main(). which one is correct ? handling exception in class or just throwing exception from class and handling in main ?,and the thing is I can no longer keep reading readAgain() from user until user enters the write input, because exception will go inside catch block and can't handle runtime error in catch block so I deleted readagain() function from design and only printed errors in main() part

exceptionHandlingV5::exceptionHandlingV5(int numerator,int denominator){
    setNumerator(numerator);
    setDenominator( denominator );
}
void exceptionHandlingV5::setDenominator(int denominator){

        if ( !denominator ){
            error = "divided by zero \n";
            throw "divided by zero\n";
        }

    (*this).denominator = denominator;
        error = "";
}

//and also I had to move obj creation 
//out of try block, and therefore 
//because of set_denominator(); handles exception
// I had to forget initializing when creating obj 
//and instead used set methods 
int main() {

     exceptionHandlingV5 ob;

    ob.setNumerator(4);

    try {
        ob.setDenominator(0);
        // logic
        cout << ob.divide();
    }
    catch(char const *e)
    {
       // I can only print errors now
       // can't keep reading
        ob.print_errors();
    }
}
solo
  • 25
  • 6
  • 4
    You're calling constructor in readAgain() aren't you. "exceptionHandlingV2 ( numerator,temp );" . The behavior is correct because you're creating new object in readAgain() and that object is getting destroyed when the function ends. – sonulohani Oct 06 '21 at 12:05
  • 2
    Also a design issue - there is no point in catching the exception in the constructor `exceptionHandlingV2::exceptionHandlingV2` as the object `exceptionHandlingV2` can't be correctly constructed with the values given. Letting the exception propagate out of the constructor is the correct design. – Richard Critten Oct 06 '21 at 12:55
  • 2
    You really shouldn't interact with the user *at all* in a constructor. – molbdnilo Oct 06 '21 at 12:58
  • @RichardCritten what do you guys think of v3 design? edited question is it perfect? or am I doing it completely wrong? – solo Oct 22 '21 at 13:40
  • @sonulohani what do you guys think of v3 design? edited question is it perfect? or am I doing it completely wrong? – solo Oct 22 '21 at 13:41
  • @molbdnilo what do you guys think of v3 design? edited question is it perfect? or am I doing it completely wrong? – solo Oct 22 '21 at 13:42
  • 1
    You're still interacting with the user, through `readAgain`. You don't even know at that point whether the zero has been calculated, read from standard input, or read from somewhere else (imagine reading a million of these from a file and having to input a new value every time a zero denominator is encountered - you would be very angry with the programmer). The proper place to handle a construction exception is outside the class. – molbdnilo Oct 22 '21 at 14:01
  • @molbdnilo thank you for revising my code , I also wrote a v4 design. I really appreciate your thoughts on that. – solo Oct 23 '21 at 07:52

1 Answers1

1

thanks to @sonulohani , @RichardCritten and @molbdnilo for guiding me and revising my stupid question ,I mean now that I look at my very first design, I see I made a lot of mistakes and errors that I got around by your helps and comments. anyway I finally revised my whole design and made a new class and main() func for division . all I wanted to do in first place was to practice runtime error handling from class, and now I think I finally got it. here is the last design. it might help someone out there in future.

#ifndef EXCEPTION_HANDLING_FINAL_V1_EXCEPTION_HANDLING_FINAL_V1_H
#define EXCEPTION_HANDLING_FINAL_V1_EXCEPTION_HANDLING_FINAL_V1_H
class exception_handling_final_v1 {
private:
    double numerator;
    double denominator;
    char * error;
public:
    exception_handling_final_v1();
    exception_handling_final_v1( double , double );

    void set_numerator ( double );
    void set_denominator ( double );

    double divide ( );
    char * errors();
};
#endif //EXCEPTION_HANDLING_FINAL_V1_EXCEPTION_HANDLING_FINAL_V1_H

#include "exception_handling_final_v1.h"
exception_handling_final_v1::exception_handling_final_v1() {
    numerator = 1;
    denominator = 1;
    error = "";
}
exception_handling_final_v1::exception_handling_final_v1( double numerator,
                                                          double denominator) {
    set_numerator( numerator );
    set_denominator ( denominator );
}
void exception_handling_final_v1::set_numerator ( double numerator ){
    (*this).numerator = numerator;
}
void exception_handling_final_v1::set_denominator( double denominator ) {
    if ( !denominator ){
        error = "denominator can not be zero\n";
        throw "denominator can not be zero\n";
    }
    (*this).denominator = denominator;
    error = "";
}
double exception_handling_final_v1 :: divide () {
    return denominator / numerator;
}
char * exception_handling_final_v1::errors() {
    return error;
}
#include <iostream>
#include "exception_handling_final_v1.h"
using namespace std;

int main() {

    exception_handling_final_v1 ob;
    double numerator , denominator , result;
    cout << "enter nummerator\n";
    cin >> numerator;
    ob.set_numerator( numerator );

    cout << "enter denominator\n";
    cin >> denominator ;

    try{
        ob.set_denominator( denominator );
        result = ob.divide();
    }
    catch( char const * error){
        cout << ob.errors();
    }

    cout<<"bye";
    return 0;
}
solo
  • 25
  • 6