Advanced Functions

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • Deanm007
    New Member
    • Apr 2010
    • 37

    Advanced Functions

    I just bought a book and he gave me an example similar to this one and forgot to explain it. Please see my notes and questions in the code and if I'm understanding anything wrong please explain. My Q's are in caps to differentiate the comments. Thanks.

    Code:
    #include <iostream>
    
    using namespace std;
    
    class Square
    {
          public:
                 Square();
                 Square(int side);
                 int GetSide() {return *itsSide;}
                 Square & operator= (Square & rhs); 
                 const Square & operator++ (); //WHY IS THIS CONST?
                 const Square operator++ (int); //WHY IS THIS CONST?
                 
          private:
                int * itsSide; //pointer to int
    };
    //default constructor
    Square::Square()
    {
    itsSide = new int(10); //Assigns new memory on heap for the calling 
                           //object and assigns 10
    }
    //overloaded constructor
    Square::Square(int side) 
    {
    itsSide = new int(side);//Assigns new memory on heap for the calling 
                           //object and assigns the passed in parameter
    }
    //overloaded assignment operator    
    Square & Square::operator= (Square & rhs)
    {
            
           delete itsSide; //WHY IS IT DELETING THE CURRENT MEMORY ADDRESS
                           //THAT THE POINTER POINTS TO?
           itsSide = new int; //Assigning new address to pointer
           *itsSide = rhs.GetSide(); //get the value for the crate object 
                                     //and assign to the new address 
           return *this; //WHAT IS BEING RETURNED HERE?
    }
    
    const Square & Square::operator++ ()
    {
          ++(itsSide); //WHY IS THIS BEING INCREMENTED WITHOUT BEING DEREFERENCED?
          return *this; //WHERE DOES THIS VALUE GET RETURNED TO?
    }
    
     const Square Square::operator++ (int)
    {
          Square temp(*this); //dereference address being passed in 
                              //and assign value to temp
          ++(itsSide); //WHY IS THIS BEING INCREMENTED WITHOUT BEING DEREFERENCED?
          return temp; //WHERE DOES THIS VALUE GET RETURNED TO?
    }       
        
    int main()
    {
        Square box; //default constructor called
        Square crate(100); //overloaded constructor called
        cout << box.GetSide() << endl; //output
        cout << crate.GetSide() << endl; //output
        
        box = crate; //overloaded assignment operator called
        cout << box.GetSide() << endl; //output
        
        
       crate++; //Overloaded postfix operator
       cout << crate.GetSide()<< endl; //WHY IS THIS RETURNING 4064624?
        
        
        
        system("pause");
        return 0;
    }
  • Banfa
    Recognized Expert Expert
    • Feb 2006
    • 9067

    #2
    WHY IS THIS CONST?

    Imagine using ints for a moment the operators at line 12 and 13 are pre and post increment, do you think either of these lines makes sense?

    Code:
    int a = 10;
    
    ++a = 7;
    a++ = 6;
    Line 4 doesn't compile, line 3 although it compiles is undefined behaviour and should be avoided. Assigning to the return value of the post or pre increment operator does not make semantic sense, the return values are effectively constants and there for the post and pre increment operators for your Square class return const. To maintain the semantic meaning of the operator.

    Code:
           delete itsSide; //WHY IS IT DELETING THE CURRENT MEMORY ADDRESS
                           //THAT THE POINTER POINTS TO?
           itsSide = new int; //Assigning new address to pointer
           *itsSide = rhs.GetSide(); //get the value for the crate object 
                                     //and assign to the new address
    Well if you have a buffer allocated using malloc inside a class normally when you copy using the assignment operator, operator=, you have to get rid of the old buffer allocate a new buffer and copy the contents of the object being copied from to the current object.

    This code maintains that strict structure. However in this particular case it is not strictly required to free and re-allocated the memory. In fact in my opinion allocating memory for a single int like this is just introducing unrequired complexity to the code. Since an int normally takes either the same number of bytes or fewer bytes to store than a pointer just having a int directly in the class either uses no extra memory or saves memory and reduces code complexity by not having all the memory allocations and releases.

    Code:
           return *this; //WHAT IS BEING RETURNED HERE?
    The current object by value.

    Code:
          ++(itsSide); //WHY IS THIS BEING INCREMENTED WITHOUT BEING DEREFERENCED?
    Almost certainly an error in the code causing undefined behaviour.

    Code:
          return *this; //WHERE DOES THIS VALUE GET RETURNED TO?
    The code that invoked the operator.

    Code:
        crate++; //Overloaded postfix operator
        cout << crate.GetSide()<< endl; //WHY IS THIS RETURNING 4064624?
    Because of the coding error in operator++

    Comment

    • Deanm007
      New Member
      • Apr 2010
      • 37

      #3
      Thanks for helping Banfa. I understand almost all your explanations. However i don't know how to fix the problem. I hate asking for answers. So maybe you can give me a hint as to what is wrong in the operator++ function?

      Comment

      • Banfa
        Recognized Expert Expert
        • Feb 2006
        • 9067

        #4
        Well in the class I would change
        int * itsSide; //pointer to int

        to
        int itsSide; //int

        and then resolve all the places treating it as a pointer but if you don't want to do that then on the lines like this

        Code:
              ++(itsSide); //WHY IS THIS BEING INCREMENTED WITHOUT BEING DEREFERENCED?
        you have correctly observed that there is an issue with dereferencing itsSide (or in fact not dereferencing it) you just need to fix it.

        Comment

        • Deanm007
          New Member
          • Apr 2010
          • 37

          #5
          I fixed the overloaded prefix operator but the post fix does not work. It outputs 0... And a new question arised: //Why not make the postfix function return a reference like the prefix function? This way, we could just return '*this'. I tried and it works. Is this ok to do? If so then why did the author go thru the hassle of creating a temp object and returning by value?

          Code:
          const Square & Square::operator++ ()
          {
                ++(*itsSide);
                return *this; 
          }
          
          
           const Square & Square::operator++ (int)
          {
                ++(*itsSide);
                return *this; 
          }
          Last edited by Deanm007; Jul 27 '10, 05:55 PM. Reason: changed caps to normal

          Comment

          • Banfa
            Recognized Expert Expert
            • Feb 2006
            • 9067

            #6
            You do know that USING CAPITALS ON THE INTERNET IS CONSIDERED TO BE SHOUTING AND RATHER RUDE do you?

            No the modification you made to postfix increment does not work because it does not implement the correct semantics.

            The semantics of postfix increment are increment the value of the object and return its original value. Your version does not do this it increments the value of the object and returns the new value which is the semantics for prefix increment.

            That is why the author uses a temporary object, its the only way to do it and because a temporary object is used the function needs to return by value not by reference hence the original implementation.

            The only change I would consider is implementing postfix increment in terms of prefix increment, in a complex class this has the effect of reducing the number of times that the incrementing logic needs to be implemented.

            Code:
            const Square Square::operator++(int)
            {
                  Square temp(*this); //dereference address being passed in 
                                      //and assign value to temp
                  ++(*this);
                  return temp;
            }
            The above logic works for any class if it has implemented prefix increment.

            Comment

            • Deanm007
              New Member
              • Apr 2010
              • 37

              #7
              Thanks for the detailed response. I didn't mean to shout. I was just trying to make the question stand out. I have made the proper changes.

              Comment

              Working...