Question in throwing a class object as exception in C++

  • C/C++
  • Thread starter yungman
  • Start date
  • Tags
    C++ Class
In summary: The called method will now do its thing and return. The object itself does not store the method. So if you say myRect.setWidth(5), the Rectangle object myRect will call the method setWidth. The object itself does not need to have a stored version of setWidth, it just needs to know where to look for the method. This is why you can call methods on objects without the compiler complaining that there's no method that exists for the object. The compiler knows where to look for the methods and how to call them, so it's happy. Now if you say Rectangle::NegativeLength e, you are not calling a method, but you are accessing the class table of Rectangle and inside
  • #1
yungman
5,718
241
This is a program from Gaddis that has two exception classes inside the Rect class. It is not clear for me how it works. Ivor book declares the exception classes as individual class, not inside another class. So I cannot compare and see what I missed in Gaddis book. Here is the program right out of the Gaddis book:
C++:
#include <iostream>
using namespace std;
class Rectangle
{
private:    double width, length;
public:
    class NegativeWidth//throw class object if w = -ve
    { private:    int value;
      public:
        NegativeWidth(int val) { value = val; }
        int getValue() const { return value; }
    };
    class NegativeLength//throw class object if len = -ve
    { private:   int value;
      public: 
        NegativeLength(int val) {value = val; }
        int getValue() const { return value; }
    };
    Rectangle()
    {   width = 0.0;
        length = 0.0;
    }
    void setWidth(double w)
    {
        if (w >= 0) width = w;
        else  throw NegativeWidth(w);//How is this an object?
    }
    void setLength(double len)
    {
        if (len >= 0)length = len;
        else  throw NegativeLength(len);//How is this an object?
    }
    double getWidth() const { return width;}
    double getLength() const{  return length;}
    double getArea() const { return width * length;}
};
int main()
{   int width, length;
    Rectangle myRect;
    cout << " Enter the rectangle's width: ";
    cin >> width;
    cout << "\n Enter the rectangle's length: ";
    cin >> length;
    try
    {   myRect.setWidth(width);
        myRect.setLength(length);
        cout<<"The area of the rectangle is "<<myRect.getArea()<<"\n\n";
    }
    catch (Rectangle::NegativeWidth e)//why not using myRect that is already defined?
    {//why not using myRect that is already defined?
        cout<<"Error: "<<e.getValue()<<" is an invalid width.\n\n";
    }
    catch (Rectangle::NegativeLength e)
    {
        cout<<"Error: " << e.getValue()<<" is an invalid length.\n\n";
    }
    cout << "End of the program.\n";
    return 0;
}

I have 3 main questions:

1) Look at line 26 and 31. throw NegativeWidth(w) and throw NegativeLength(len). These are Constructors of the two classes, not object of NegativeWidth and NegativeLength . Are we supposed to throw OBJECT only?

2) Also, look at line 49 and 53. They declared object by (Rectangle::NegativeWidth e) and (Rectangle::NegativeLength e). But the program already declared Rectangle myRect. Why not use the NegativeWidth in myRect instead instead of starting a new object using (Rectangle::NegativeWidth e)

3) In Ivor book, it would put class NegativeWidth and class NegativeLength as derived class of Rectangle. This makes things so much simpler. Is what Gaddis way of declaring class inside another class a good way to do things? I just want to confirm because you guys had criticized Gaddis' sample programs in his later chapters already.

Thanks
 
Last edited:
Technology news on Phys.org
  • #2
Hi yungman,

yungman said:
1) Look at line 26 and 31. throw NegativeWidth(w) and throw NegativeLength(len). These are Constructors of the two classes, not object of NegativeWidth and NegativeLength . Are we supposed to throw OBJECT only?
Code:
return NegativeWidth(w)
will in fact create an object of type NegativeWidth and then return it to be thrown. So you do throw an object in both cases (line 26 and 31). Note: this is equivalent to writing
Code:
NegativeWidth error = NegativeWidth(w);
throw error;
If you call the constructor directly in the line as the throw statement, it will first call the constructor creating an object and then return that object.

yungman said:
2) Also, look at line 49 and 53. They declared object by (Rectangle::NegativeWidth e) and (Rectangle::NegativeLength e). But the program already declared Rectangle myRect. Why not use the NegativeWidth in myRect instead instead of starting a new object using (Rectangle::NegativeWidth e)
(Rectangle::NegativeLength e) does not declare a new object, but is just indicating the type of e (like a function signature tells the functions what types to expect). This allows to handle different error types differently. In this case it's not that important, because NegativeLength and NegativeWidth are pretty much the same thing. But think of something like opening files from os. You would certainly want to handle a FileNotFoundException differently than a PermissionDeniedException.

If you instead used myRect::NegativeLength e, this would also work, but there is really no benefit to it. You would not need to have a Rectangle defined in order to access the type Rectangle::NegativeLength. When the compiler (or linker, I'm not a 100% sure which one does this) reaches this statement it will search for the definition of the type, which is part of the Rectangle class. It would do a similar thing for myRect, but it would have to resolve one reference more than when directly calling Rectangle. A fundamental thing to understand is, that an object of a class does not individually store all the declared methods of the class (if you had 100 objects that would lead to 100 times the exact same implementation, which is of course redundant), instead it stores only its personal variables, plus a reference to its class table, in which there's references to the individual methods. If you now call a method (or constructor in that case), the object it was called on (myRect) will notice, that it is not part of its individual implementations and will hand that request to the class it belongs to (this continues for any existing parent class until a method/field is found or a compiler error is thrown) and this class (Rectangle) will then handle the request. You see, myRect really doesn't do anything here, so you don't need to call the constructor via myRect.

yungman said:
3) In Ivor book, it would put class NegativeWidth and class NegativeLength as derived class of Rectangle. This makes things so much simpler. Is what Gaddis way of declaring class inside another class a good way to do things? I just want to confirm because you guys had criticized Gaddis' sample programs in his later chapters already.
I think this is personal preference. Personally I'd probably not derive NegativeWidth (and Length) from Rectangle, making the argument that when deriving from a class, it will inherit all the fields and methods from the parent, which is totally useless if it's only used to throw an error.Is this helpful?
 
Last edited:
  • Like
Likes yungman
  • #3
randy said:
Hi yungman,
Code:
return NegativeWidth(w)
will in fact create an object of type NegativeWidth and then return it to be thrown. So you do throw an object in both cases (line 26 and 31). Note: this is equivalent to writing
Code:
NegativeWidth error = NegativeWidth(w);
throw w;
If you call the constructor directly in the line as the throw statement, it will first call the constructor creating an object and then return that object.
.....
Thanks Randy
I still need to spend time to read the second part. I first want to verify that you meant throw error instead of throw w. w is a number. error is object of class NegativeWidth.

Thanks
 
  • #4
Oh you're totally right I meant error, thanks for correcting
 
  • Like
Likes yungman
  • #5
randy said:
....
(Rectangle::NegativeLength e) does not declare a new object, but is just indicating the type of e (like a function signature tells the functions what types to expect). This allows to handle different error types differently. In this case it's not that important, because NegativeLength and NegativeWidth are pretty much the same thing. But think of something like opening files from os. You would certainly want to handle a FileNotFoundException differently than a PermissionDeniedException.

If you instead used myRect::NegativeLength e, this would also work, but there is really no benefit to it. You would not need to have a Rectangle defined in order to access the type Rectangle::NegativeLength. When the compiler (or linker, I'm not a 100% sure which one does this) reaches this statement it will search for the definition of the type, which is part of the Rectangle class. It would do a similar thing for myRect, but it would have to resolve one reference more than when directly calling Rectangle. A fundamental thing to understand is, that an object of a class does not individually store all the declared methods of the class (if you had 100 objects that would lead to 100 times the exact same implementation, which is of course redundant), instead it stores only its personal variables, plus a reference to its class table, in which there's references to the individual methods. If you now call a method (or constructor in that case), the object it was called on (myRect) will notice, that it is not part of its individual implementations and will hand that request to the class it belongs to (this continues for any existing parent class until a method/field is found or a compiler error is thrown) and this class (Rectangle) will then handle the request. You see, myRect really doesn't do anything here, so you don't need to call the constructor via myRect.

I think this is personal preference. Personally I'd probably not derive NegativeWidth (and Length) from Rectangle, making the argument that when deriving from a class, it will inherit all the fields and methods from the parent, which is totally useless if it's only used to throw an error.

Is this helpful?
Thanks for you detail response. I still have questions:

I thought (Rectangle::NegativeLength e) is declaration of an object e. You can see line 51 and 55, the program use e.getValue. That shows e is an object that contain member function getValue().

Also, the reason I asked about why not using myRect::NegativeLength e is because I did try changing (Rectangle::NegativeWidth e) to (myRect::NegativeWidth e), VS gave me error. I could not do that. I agree with you that I should be able to do that, be it unwise, but it should be OK. My question is why can't I write (myRect::NegativeWidth e)?

Thanks
 
  • #6
yungman said:
I thought (Rectangle::NegativeLength e) is declaration of an object e. You can see line 51 and 55, the program use e.getValue. That shows e is an object that contain member function getValue().
e is an object all right, an instance of the NegativeLength member of Rectangle. NegativeLength is itself a class.
yungman said:
Also, the reason I asked about why not using myRect::NegativeLength e is because I did try changing (Rectangle::NegativeWidth e) to (myRect::NegativeWidth e), VS gave me error. I could not do that. I agree with you that I should be able to do that, be it unwise, but it should be OK. My question is why can't I write (myRect::NegativeWidth e)?
myRect is not a type (the name of a class in this case) -- it is an instance of a class, i.e., an object. In what you're asking about, you need to provide the type of e, which is Rectangle::NegativeWidth.

If myRect is a Rectangle object, then you can access its NegativeWidth and NegativeLength (class) members like this: myRect.NegativeWidth or myRect.NegativeLength, but these are values, not types.

Notice the difference between the type Rectangle::NegativeWidth and the value myRect.NegativeWidth; particularly the use of :: in the first and the period (.) in the second.

For a simpler example, consider this declaration: int var;
The type of the variable is int, but var gives its value.
 
  • Like
Likes yungman
  • #7
Mark44 said:
e is an object all right, an instance of the NegativeLength member of Rectangle. NegativeLength is itself a class.
myRect is not a type (the name of a class in this case) -- it is an instance of a class, i.e., an object. In what you're asking about, you need to provide the type of e, which is Rectangle::NegativeWidth.

If myRect is a Rectangle object, then you can access its NegativeWidth and NegativeLength (class) members like this: myRect.NegativeWidth or myRect.NegativeLength, but these are values, not types.

Notice the difference between the type Rectangle::NegativeWidth and the value myRect.NegativeWidth; particularly the use of :: in the first and the period (.) in the second.

For a simpler example, consider this declaration: int var;
The type of the variable is int, but var gives its value.
Thanks Mark.

That is really what my original post trying to ask. If you put a class inside a class, it gets confusing. Yes, I did try myRect.NegativeLength, which you said is a value, what value?

If NegativeLength is a class, how do you create an object of NegativeLength inside myRect? I tried put in a line of code myRect.NegativeLength negL to try to create an object negL of myRect.NegativeLength, VS gave me an error. This class inside a class seems to tangle up things. What is the reason of doing this versus just simple bass and derived class? Simple bass and derived class is just so much cleaner and simpler.

That's my whole question of this thread. I can just change the program a little into base and derived class and it would be very easy and direct. That's why I want to hear from the experts here whether this program is even good way to demo exception using class object.

But like before, you guys might give me example why this way is important.

Thanks
 
  • #8
I want to show the program from Ivor book on calling different class object for exception. It is simple and straight forward.
C++:
//Matching catch handler with exception
#include<iostream>
#include<string>
#include<string_view>
#include<cstring>
using namespace std;
class Trouble
{
private: 
public:
    string message;
    Trouble(string_view str = " There is a problem")//12, 12, 
        { message = str; }//30, 31, 19,
    virtual ~Trouble() = default;//Base classes must have virtual des.
    virtual string_view what() const { return message; }// 
};
class MoreTrouble : public Trouble
{
 public: MoreTrouble(string_view str = " Theres more trouble")//19, 19, 
    : Trouble(str){}//11, 11, 25, 
      ~MoreTrouble() { cout << " Destructor MoreTrouble.\n\n"; }
};
class BigTrouble : public MoreTrouble
{
public: BigTrouble(string_view str = " Really big trouble") //25, 
    : MoreTrouble(str) {};//18, 32, 
      ~BigTrouble() { cout << " Destructor BigTrouble.\n\n"; }
};
int main()
{    Trouble trouble;//11, 
    MoreTrouble moreTrouble; //18, 
    BigTrouble bigTrouble;//24, 
   
    for (int i = 0; i < 7; ++i)
    {    try
        {
            if (i == 3) throw trouble;// 
            else if (i == 5) throw moreTrouble;//
            else if (i == 6) throw bigTrouble;        }
        catch (const BigTrouble& t) { cout << " BigTrouble obj caught: " <<
            t.what() << "\n\n"; }//
        catch (const MoreTrouble& t) { cout << " MoreTrouble obj caught: " <<//
            t.what() << "\n\n"; }// 
        catch (const Trouble& t) { cout << " Trouble obj caught: " <<//
            t.what() << "\n\n"; }//
        cout << " End of for loop(after catch blocks), i = " << i << "\n\n";
    }
}
This program calling objects of 3 different classes depending on the condition, it is simple and straight forward. Anything the Gaddis program can do that this simple one cannot?
 
  • #9
yungman said:
That is really what my original post trying to ask. If you put a class inside a class, it gets confusing. Yes, I did try myRect.NegativeLength, which you said is a value, what value?
What value do you think it could be? It is not something that you would ever want to use anyway.

yungman said:
If NegativeLength is a class, how do you create an object of NegativeLength inside myRect?
You would never want to do this. The only reason to create a NegativeLength object is to throw it to be caught by an exception handler, not tuck it away as a class member. Also stop using the word 'inside' in this way, it is confusing you.

yungman said:
I tried put in a line of code myRect.NegativeLength negL to try to create an object negL of myRect.NegativeLength, VS gave me an error.
Yes, because myRect.NegativeLength is not the name of type.

yungman said:
This class inside a class seems to tangle up things. What is the reason of doing this versus just simple bass and derived class? Simple bass and derived class is just so much cleaner and simpler.
It would be nonsense to derive an exception class in this way because an exception is not a special kind of rectangle.

It is standard practice in many modern languages to add 'Exception' or 'Error' to the end of the name of exceptions (so the class would be Rectangle::NegativeLengthException) to avoid any confusion. In the c++ world there is less consistency and we have exceptions like bad_alloc and runtime_error. I don't know why neither of your books follow either practice.

yungman said:
I want to show the program from Ivor book on calling different class object for exception. It is simple and straight forward.

This program calling objects
You can't call an object. It is very important that you use the right terminology for two reasons:
  1. to reduce your confusion
  2. so that we know what you do understand and what you don't.
yungman said:
of 3 different classes depending on the condition, it is simple and straight forward. Anything the Gaddis program can do that this simple one cannot?
Yes, it enables you to write code like this:
C++:
try {
  // Do something that might cause an exception.
} catch (const Rectangle::NegativeLengthException& err) {
  // Handle rectangles with negative length.
} catch (const Cylinder::NegativeLengthException& err) {
  // Handle cylinders with negative length.
} catch (...) {
  // Handle anything else.
}
 
  • #10
pbuk said:
What value do you think it could be? It is not something that you would ever want to use anyway.
Mark said it's a value, that's why I ask what value. I don't see a value from it.

pbuk said:
You would never want to do this. The only reason to create a NegativeLength object is to throw it to be caught by an exception handler, not tuck it away as a class member. Also stop using the word 'inside' in this way, it is confusing you.
Then why put it inside? That's my question in this thread. Would it be just as easy and much clearer to just put a separate class NegativeLength{}, create an object of this and throw as exception?

pbuk said:
Yes, because myRect.NegativeLength is not the name of type.
I am not saying it makes sense, I am saying if NegativeLength is a class, then I SHOULD be able to create an object out of it. If you say it CANNOT, then it's a different story and it is inconsistent with "class".

pbuk said:
It would be nonsense to derive an exception class in this way because an exception is not a special kind of rectangle.
Then is it better off put NegativeLength class as a separate class outside and independent to the Rect? That's my whole point of this thread. Why even do it this way.

pbuk said:
It is standard practice in many modern languages to add 'Exception' or 'Error' to the end of the name of exceptions (so the class would be Rectangle::NegativeLengthException) to avoid any confusion. In the c++ world there is less consistency and we have exceptions like bad_alloc and runtime_error. I don't know why neither of your books follow either practice.You can't call an object. It is very important that you use the right terminology for two reasons:
  1. to reduce your confusion
  2. so that we know what you do understand and what you don't.
Yes, I should say throw an object.

pbuk said:
Yes, it enables you to write code like this:
C++:
try {
  // Do something that might cause an exception.
} catch (const Rectangle::NegativeLengthException& err) {
  // Handle rectangles with negative length.
} catch (const Cylinder::NegativeLengthException& err) {
  // Handle cylinders with negative length.
} catch (...) {
  // Handle anything else.
}

Thanks for the reply. I know what it's trying to do, but the way it's done is confusing. My ultimate question is whether it is wise to do it this way? Seems like it can be done better if the exception class is better off being a separate independent class instead of nesting inside another class.

Thanks
 
Last edited by a moderator:
  • #11
yungman said:
Mark said it's a value, that's why I ask what value. I don't see a value from it.
Your question was about e, which is an object, not a type. An object has a value, where a type does not. The objects in question have one data member each, named value. If you run the code and enter a negative value for width or length, you can see an e object and its value.
yungman said:
Then why put it inside? That's my question in this thread. Would it be just as easy and much clearer to just put a separate class NegativeLength{}, create an object of this and throw as exception?
Because the NegativeLength and NegativeWidth classes are intimately tied to the Rectangle class. They prevent the width and length members of a Rectangle object from being set to negative values. The accompanying code for setLength() and setLength() throw instances of these two classes as exceptions if an attempt is made to set either to a negative value. If you declared these two classes outside of Rectangle, then the connection to the Rectangle class would be lost.
yungman said:
am not saying it makes sense, I am saying if NegativeLength is a class, then I SHOULD be able to create an object out of it. If you say it CANNOT, then it's a different story and it is inconsistent with "class".
e is an object of the NegativeLength or NegativeWidth class. As @pbuk said, it would be better style for these classes to have Exception as part of their names. Look at the code in the two catch blocks where the two e objects are being declared.
yungman said:
Then is it better off put NegativeLength class as a separate class outside and independent to the Rect? That's my whole point of this thread.
No, as explained above.
yungman said:
Why even do it this way.
Also explained above.

BTW, the code you showed in post 1 caused several warnings. The data members in Rectangle are type double, but the NegativeWidth/Length classes have a member that is an int. To eliminate the warnings I made all variables of the dimensions of type int. If this code was taken verbatim from Ivor, it's sloppy.
 
  • Like
Likes yungman
  • #12
yungman said:
Then is it better off put NegativeLength class as a separate class outside and independent to the Rect? That's my whole point of this thread. Why even do it this way?
Several reasons:
1) Doing it this way allows the compiler to enforce that the NegativeLength exception can only come from the parts of your program that create and manage Rectangle objects. That’s not a concern with the toy programs used in examples and exercises, but in a real application you will have many hundreds or thousands of classes to keep straight, and likely tens of people working on the code at the same time.
2) If you are writing a real application, chances are that it will support shapes other than rectangles; @pbuk showed above how you might incorporate (for example) cylinders or other shapes which will need their own exceptions. Having classes Cylinder::NegativeLength and Rectangle::NegativeLength and so forth is the natural way of doing this.
3) Perhaps most important: the nested class Rectangle::NegativeLength has access to the internal structure of Rectangle, so can gather whatever information is needed to make the exception useful to the error handler. Again, that doesn’t matter for this toy example where all we have is one negative number to know about but it matters in real applications.
 
  • Like
Likes yungman
  • #13
Mark44 said:
e is an object of the NegativeLength or NegativeWidth class. As @pbuk said, it would be better style for these classes to have Exception as part of their names. Look at the code in the two catch blocks where the two e objects are being declared.

And better style for e to have a more descriptive name.
 
  • #14
Mark44 said:
Your question was about e, which is an object, not a type. An object has a value, where a type does not. The objects in question have one data member each, named value. If you run the code and enter a negative value for width or length, you can see an e object and its value.
I think the responses got crossed here. I was referring to what you said in post 6:
Mark44 said:
If myRect is a Rectangle object, then you can access its NegativeWidth and NegativeLength (class) members like this: myRect.NegativeWidth or myRect.NegativeLength, but these are values, not types.
NegativeWidth is a class, the object of NegativeWidth can return a value only when using NegativeWidth.getW().

Mark44 said:
Because the NegativeLength and NegativeWidth classes are intimately tied to the Rectangle class. They prevent the width and length members of a Rectangle object from being set to negative values. The accompanying code for setLength() and setLength() throw instances of these two classes as exceptions if an attempt is made to set either to a negative value. If you declared these two classes outside of Rectangle, then the connection to the Rectangle class would be lost.
e is an object of the NegativeLength or NegativeWidth class. As @pbuk said, it would be better style for these classes to have Exception as part of their names. Look at the code in the two catch blocks where the two e objects are being declared.
No, as explained above.
Also explained above.

BTW, the code you showed in post 1 caused several warnings. The data members in Rectangle are type double, but the NegativeWidth/Length classes have a member that is an int. To eliminate the warnings I made all variables of the dimensions of type int. If this code was taken verbatim from Ivor, it's sloppy.

The program in post 1 is from Gaddis program 16.5. Yes, it is word for word of the program. I think I literally copied the code from his CD. Only thing I did is combined the .h and .cpp into the source.cpp for easier to read. Ivor examples are better.

I am kind of following Gaddis to the end but using other book as supplement. Kind of too late to change ship, this is about the last chapter. I can go to Schaum's book for the rest of the data structure.Thanks
 
Last edited by a moderator:
  • #15
Mark44 said:
If myRect is a Rectangle object, then you can access its NegativeWidth and NegativeLength (class) members like this: myRect.NegativeWidth or myRect.NegativeLength, but these are values, not types.
yungman said:
NegativeWidth is a class, the object of NegativeWidth can return a value only when using NegativeWidth.getW().
Right. What I wrote is incorrect. To get access to either of the nested classes, you have to create an object of that type, like so:
Rectangle::NegativeWidth nw;
Then you can use the getValue() method. Same for the NegativeLength class.
The object being caught in the two catch blocks (e in both) is declared this way.
yungman said:
The program in post 1 is from Gaddis program 16.5. Yes, it is word for word of the program.
Nope, it's not word for word. In Gaddis's code, the type of value (the data member of each of the nested classes) is double, not int as you wrote.

Also, please be more careful when you're quoting someone. If you do the quotes right, you don't need to color anything.
 
  • #16
Mark44 said:
Right. What I wrote is incorrect. To get access to either of the nested classes, you have to create an object of that type, like so:
Rectangle::NegativeWidth nw;
Then you can use the getValue() method. Same for the NegativeLength class.
The object being caught in the two catch blocks (e in both) is declared this way.
Nope, it's not word for word. In Gaddis's code, the type of value (the data member of each of the nested classes) is double, not int as you wrote.

Also, please be more careful when you're quoting someone. If you do the quotes right, you don't need to color anything.
I don't know what Gaddis you are looking. This is the original code DIRECTLY from the CD:

C++:
// Specification file for the Rectangle class
#ifndef RECTANGLE_H
#define RECTANGLE_H

class Rectangle
{
   private:
      double width;     // The rectangle's width
      double length;    // The rectangle's length
   public:
      // Exception class for a negative width
      class NegativeWidth
      {
      private:
         int value;
      public:
         NegativeWidth(int val)
            { value = val; }

         int getValue() const
            { return value; }
      };
    
      // Exception class for a negative length
      class NegativeLength
      {
      private:
         int value;
      public:
         NegativeLength(int val)
            { value = val; }

         int getValue() const
            { return value; }
      };

      // Default constructor
      Rectangle()
         { width = 0.0; length = 0.0; }
    
      // Mutator functions, defined in Rectangle.cpp
      void setWidth(double);
      void setLength(double);
    
      // Accessor functions
      double getWidth() const
         { return width; }

      double getLength() const
         { return length; }

      double getArea() const
         { return width * length; }
};
#endif

C++:
// Implementation file for the Rectangle class.
#include "Rectangle.h"

//***********************************************************
// setWidth sets the value of the member variable width.    *
//***********************************************************

void Rectangle::setWidth(double w)
{
   if (w >= 0)
      width = w;
   else
      throw NegativeWidth(w);
}

//***********************************************************
// setLength sets the value of the member variable length.  *
//***********************************************************

void Rectangle::setLength(double len)
{
   if (len >= 0)
      length = len;
   else
      throw NegativeLength(len);
}

C++:
#include <iostream>
using namespace std;
class Rectangle
{
private:    double width, length;
public:
    class NegativeWidth//throw class object if w = -ve
    { private:    int value;
      public:
        NegativeWidth(int val) { value = val; }
        int getValue() const { return value; }
    };
    class NegativeLength//throw class object if len = -ve
    { private:   int value;
      public: 
        NegativeLength(int val) {value = val; }
        int getValue() const { return value; }
    };
    Rectangle()
    {   width = 0.0;
        length = 0.0;
    }
    void setWidth(double w)
    {
        if (w >= 0) width = w;
        else  throw NegativeWidth(w);//How is this an object?
    }
    void setLength(double len)
    {
        if (len >= 0)length = len;
        else  throw NegativeLength(len);//How is this an object?
    }
    double getWidth() const { return width;}
    double getLength() const{  return length;}
    double getArea() const { return width * length;}
};
int main()
{   int width, length;
    Rectangle myRect;
    cout << " Enter the rectangle's width: ";
    cin >> width;
    cout << "\n Enter the rectangle's length: ";
    cin >> length;
    try
    {   myRect.setWidth(width);
        myRect.setLength(length);
        cout<<"The area of the rectangle is "<<myRect.getArea()<<"\n\n";
    }
    catch (Rectangle::NegativeWidth e)//why not using myRect that is already defined?
    {//why not using myRect that is already defined?
        cout<<"Error: "<<e.getValue()<<" is an invalid width.\n\n";
    }
    catch (Rectangle::NegativeLength e)
    {
        cout<<"Error: " << e.getValue()<<" is an invalid length.\n\n";
    }
    cout << "End of the program.\n";
    return 0;
}

I did change to shorten the cout sentences(nothing to do with the program). Only other name I change is instead of myRectangle, I use myRect.. Value is always integer.

Yes, I did combined them together into one file. But other than that, I did not change the program.
 
  • #17
yungman said:
Value is always integer.
It should be type double.
C++:
    class NegativeWidth
      {
      private:
         int value;                              // here
      public:
         NegativeWidth(int val)     // and here
            { value = val; }
And exactly the same problem in the NegativeLength class.
The width and length members of Rectangle are double. If a negative width or length is entered, value should be of the same type, not int. The compiler won't issue an error, but it will issue a warning. That's sloppy coding, and it's what I was talking about.
 
  • Like
Likes pbuk
  • #18
Mark44 said:
It should be type double.
C++:
    class NegativeWidth
      {
      private:
         int value;                              // here
      public:
         NegativeWidth(int val)     // and here
            { value = val; }
And exactly the same problem in the NegativeLength class.
The width and length members of Rectangle are double. If a negative width or length is entered, value should be of the same type, not int. The compiler won't issue an error, but it will issue a warning. That's sloppy coding, and it's what I was talking about.
What book edition are you using, this is 6th.
 
  • Sad
Likes pbuk
  • #19
yungman said:
What book edition are you using, this is 6th.
It doesn't matter what edition of any book is involved, get your head out of the book and look at the code. On line 5 of the code you wrote:

yungman said:
C++:
#include <iostream>
using namespace std;
class Rectangle
{
private:    double width, length;
you declare width and length as doubles. On lines 33-35 you use these variables in functions which are correctly declared to return doubles.

yungman said:
C++:
    double getWidth() const { return width;}
    double getLength() const{  return length;}
    double getArea() const { return width * length;}

On line 26 you create a Rectangle::NegativeWidth object by calling its class's constructor (that is how we create objects in c++!). We pass w, which is a double, as a parameter.
yungman said:
C++:
        else  throw NegativeWidth(w);//How is this an object?

We haven't defined a constructor for the Rectangle::NegativeWidth class that takes a double so the compiler looks for the next best thing and finds it on line 10:
yungman said:
C++:
        NegativeWidth(int val) { value = val; }
This constructor expects an int so the compiler downgrades the double value of w to an int. This can cause loss of information so the compiler issues a warning. You should correct this because the whole point of using exceptions in c++ (or any other language that supports them) is to make your code more reliable, not to introduce more bugs with sloppy coding.
 
Last edited:
  • Like
Likes jbunniii and Vanadium 50
  • #20
pbuk said:
It doesn't matter what edition of any book is involved, get your head out of the book and look at the code.

+1000
 
  • #21
yungman said:
What book edition are you using, this is 6th.
I'm looking at the 6th ed.

Your code doesn't match the code in the book. I've explained how it doesn't match and where to look.
 
  • #22
Mark44 said:
I'm looking at the 6th ed.

Your code doesn't match the code in the book. I've explained how it doesn't match and where to look.
I got it from the book's CD.
 
  • #23
yungman said:
I got it from the book's CD.
I don't have the CD, so I can't check. Does the code on the CD for the NegativeWidth() and NegativeLength() constructors have an argument of type int or type double? The argument for each should be type double to match the data members in the Rectangle class.

This is very simple: if the CD code has int parameters, then it's an oversight by Gaddis. OTOH, if the type is double, then this is something you overlooked.
 
  • #24
Mark44 said:
I don't have the CD, so I can't check. Does the code on the CD for the NegativeWidth() and NegativeLength() constructors have an argument of type int or type double? The argument for each should be type double to match the data members in the Rectangle class.

This is very simple: if the CD code has int parameters, then it's an oversight by Gaddis. OTOH, if the type is double, then this is something you overlooked.
I copied the code straight from the CD that came with the book in post 16, please don't accuse me of making false statement. Besides, what is the big deal using int? This is a multiplication problem, int X int = int no matter who you cut it.

When the book said the program is in the CD, I take their words and NOT compare back to the book.
 
  • #25
yungman said:
Besides, what is the big deal using int? This is a multiplication problem, int X int = int no matter who you cut it.
You're missing the point - this is not about multiplying two int values. The width and length data members of the Rectangle class are type double, but the NegativeWidth() and NegativeLength() constructor parameters and value data members are type int. That's a mismatch.
 
  • Like
Likes pbuk
  • #26
yungman said:
I copied the code straight from the CD that came with the book in post 16
Well maybe the author included a few deliberate errors as an exercise to make sure you understand what you are doing instead of just copying.

yungman said:
Besides, what is the big deal using int?
This was explained in messages #15, #17, #19 and now #25 of this post; is there something you do not understand in those explanations?
 
  • Like
Likes Vanadium 50
  • #27
pbuk said:
Well maybe the author included a few deliberate errors as an exercise to make sure you understand what you are doing instead of just copying.
Really? Perhaps you're being, errr, wry? If you were his publisher and you learned of such a thing, wouldn't you be livid? :wink:
Besides, what is the big deal using int?
This was explained in messages #15, #17, #19 and now #25 of this post; is there something you do not understand in those explanations?
Yeah, that seems a bit nonchalant to me, too.
 
  • #28
Mark44 said:
You're missing the point - this is not about multiplying two int values. The width and length data members of the Rectangle class are type double, but the NegativeWidth() and NegativeLength() constructor parameters and value data members are type int. That's a mismatch.
No I am not, this is an exercise only, even if it were to declare double, I NEVER enter anything with decimals to test the program. Like 2, 3, -1, -3. The point is if the program say integer, just put integer.

I am very literal, if the book provide me the code, I take it literally and not wasting time question on whether it's int or double. My emphasis is on why the program using the class inside and how to interpreted the declaration.
 
  • Sad
Likes Mark44
  • #29
pbuk said:
Well maybe the author included a few deliberate errors as an exercise to make sure you understand what you are doing instead of just copying.This was explained in messages #15, #17, #19 and now #25 of this post; is there something you do not understand in those explanations?
You read my respond? I COPIED STRAIGHT OUT OF THE CD GIVEN BY THE BOOK. I did not make the change.
 
  • #30
Wow, @yungman, isn't it clear that in that part of his post, @pbuk was responding to your asking rhetorically "Besides, what's the big deal using int"? ##-## regarding the earlier part of the post, we're all fully aware that you said you copied straight from the CD ##-## did you do a copy and paste, or did you print it and then type it in?
 
  • Like
Likes Mark44
  • #31
yungman said:
You read my respond? I COPIED STRAIGHT OUT OF THE CD GIVEN BY THE BOOK.

You've said this before and it was not true then. I don't think it's true now.

It's time to face an unfortunate and unpleasant fact: you are not a very good programmer. The reason you are not a very good programmer is twofold:
  1. You have clearly not understood the material in the earlier sections but have gone on to later sections. You have not grasped the concept of pointers (chapter 9), arrays (chapter 7), or variable typing (chapter 2).
  2. You ignore our attempts to help you. There are literally thousands of messages trying to help you and you make us repeat the same things many, many times. (see #15, #17, #19 and now #25 )
Thus far, you've blamed your book, me, your compilers, PF, your printer and your washing machine. None of them are at fault here. This is all of your doing.

You have a decision to make. You can try and become a better programmer which means changing your behavior, or you can keep doing what you're doing and remain poor at programming. Up to you.
 
Last edited:
  • Like
Likes Mark44, jbunniii and pbuk
  • #32
yungman said:
No I am not, this is an exercise only, even if it were to declare double, I NEVER enter anything with decimals to test the program. Like 2, 3, -1, -3. The point is if the program say integer, just put integer.

I am very literal, if the book provide me the code, I take it literally and not wasting time question on whether it's int or double. My emphasis is on why the program using the class inside and how to interpreted the declaration.
No offense, but this attitude would get you nowhere in a professional or open-source project. A pull request where the author doesn't care about implicit narrowing of double to int because "I NEVER enter anything with decimals to test the program" is a pull request that's going to be declined by any competent software team.

Type safety (e.g. ensuring that the objects provided to a function are of the type expected by the function) is a hugely important theme in C++. Unfortunately, to maintain compatibility with C, it isn't enforced by the compiler for many legacy "plain old data" types such as double and int. This is a major source of bugs, which is why most compilers will emit a warning in this case. (If yours does not, then find the setting to enable warnings for implicit narrowing. Also, you should enable the setting to "treat warnings as errors" instead of ignoring or disabling warnings!)
 
Last edited:
  • Like
Likes pbuk, sysprog, Mark44 and 1 other person
  • #33
jbunniii said:
implicit narrowing

I agree implicit narrowing is a problem. But here I think that's not the problem.
  • If the variable will always hold an integer, it should be an int. Period. It should never be a double anywhere in the code.
  • If the variable will sometimes be fractional, it should never be an int. Period.
The problem is not implicit narrowing. The problem is a lack of clear thinking about what this variable is supposed to represent.Other problems flow from this.
 
  • Like
Likes sysprog
  • #34
Vanadium 50 said:
I agree implicit narrowing is a problem. But here I think that's not the problem.
  • If the variable will always hold an integer, it should be an int. Period. It should never be a double anywhere in the code.
  • If the variable will sometimes be fractional, it should never be an int. Period.
The problem is not implicit narrowing. The problem is a lack of clear thinking about what this variable is supposed to represent.Other problems flow from this.
Absolutely agree that this is the underlying problem. My suggestion about enabling the implicit narrowing warning is that it makes it much easier to recognize errors like this in the first place. If @yungman had enabled this warning along with "treat warnings as errors", he would have been aware of, and perhaps fixed, the problem before posting his code here. (Or, if not clear what the problem is and how to proceed, he could have asked about it here!)

This is even more important if he's using code from a CD and assuming that it's correct.
 
  • #35
jbunniii said:
If @yungman had enabled this warning along with "treat warnings as errors", he would have been aware of, and perhaps fixed, the problem before posting his code here.
Like myself, yungman is using Visual Studio, for which the default warning level is W3, one lower than the highest warning level (which treats warnings as errors). When I first ran the code I got the warning about conversion from double to int. I'm almost certain he got the same warning, assuming he compiled and ran the code.
 
Last edited:
  • Like
Likes jbunniii
<h2>1. What is a class object in C++?</h2><p>A class object in C++ is an instance of a class, which is a user-defined data type that encapsulates data and functions. It can be thought of as a blueprint for creating objects with specific attributes and behaviors.</p><h2>2. How do you throw a class object as an exception in C++?</h2><p>To throw a class object as an exception in C++, you can use the <code>throw</code> keyword followed by the object you want to throw. This will send an exception of that object's type to the nearest <code>catch</code> block in the program.</p><h2>3. Why would you throw a class object as an exception in C++?</h2><p>Throwing a class object as an exception in C++ allows you to handle different types of errors or exceptional situations in your program. By creating custom class objects to represent specific exceptions, you can provide more detailed information about the error and how to handle it.</p><h2>4. Can you catch a class object as an exception in C++?</h2><p>Yes, you can catch a class object as an exception in C++. When an exception is thrown, the program will search for a <code>catch</code> block that matches the type of the thrown object. If a match is found, the code inside that <code>catch</code> block will be executed.</p><h2>5. How can you handle a thrown class object exception in C++?</h2><p>To handle a thrown class object exception in C++, you can use a <code>try-catch</code> block. The code that may throw an exception is placed inside the <code>try</code> block, and the corresponding <code>catch</code> block will handle the exception if it occurs. You can also use multiple <code>catch</code> blocks to handle different types of exceptions.</p>

1. What is a class object in C++?

A class object in C++ is an instance of a class, which is a user-defined data type that encapsulates data and functions. It can be thought of as a blueprint for creating objects with specific attributes and behaviors.

2. How do you throw a class object as an exception in C++?

To throw a class object as an exception in C++, you can use the throw keyword followed by the object you want to throw. This will send an exception of that object's type to the nearest catch block in the program.

3. Why would you throw a class object as an exception in C++?

Throwing a class object as an exception in C++ allows you to handle different types of errors or exceptional situations in your program. By creating custom class objects to represent specific exceptions, you can provide more detailed information about the error and how to handle it.

4. Can you catch a class object as an exception in C++?

Yes, you can catch a class object as an exception in C++. When an exception is thrown, the program will search for a catch block that matches the type of the thrown object. If a match is found, the code inside that catch block will be executed.

5. How can you handle a thrown class object exception in C++?

To handle a thrown class object exception in C++, you can use a try-catch block. The code that may throw an exception is placed inside the try block, and the corresponding catch block will handle the exception if it occurs. You can also use multiple catch blocks to handle different types of exceptions.

Similar threads

  • Programming and Computer Science
Replies
4
Views
783
  • Programming and Computer Science
Replies
19
Views
979
  • Programming and Computer Science
2
Replies
36
Views
2K
  • Programming and Computer Science
Replies
17
Views
1K
  • Programming and Computer Science
Replies
31
Views
2K
  • Programming and Computer Science
2
Replies
39
Views
3K
  • Programming and Computer Science
Replies
23
Views
2K
  • Programming and Computer Science
Replies
3
Views
1K
Replies
10
Views
2K
  • Programming and Computer Science
Replies
23
Views
1K
Back
Top