CS62 - Spring 2010 - Lecture 22

  • admin
       - liaisons
          - send e-mail asap
       - TAs
          - will forward e-mail soon

  • exercises 3-18 and 3-15

  • An aside: Functionally, is there any difference between:
       x = x + 1;
       x += 1;

       - they all end up with x being one larger than what it was before
       - However... there is a difference, which can be seen in the following:
          y = x = x+1;
          y = x += 1;
          y = x++;

          (similarly you could print out the values using System.out.println)
          - what will be the value of y?
             - in the first two, the value is one more than x
             - in the last, it is x

  • Last time we did the following:
       int x = 10;
       int* xPtr = &x;
       (*xPtr++) = 20;

       cout << *xPtr << endl;

       and couldn't figure out why the value printed out was a random integer (and not 20).

       - why is this?
          - like our example above, the ++ operator increments the value of xPtr, however, it returns the original value of xPtr. So what we end up changing is the value of x, not the new value that xPtr points to.

  • Look at Simple.java in big3.cpp code
       - what does this print out? why?
          - 0
          - if an object is used in the context of a String, it's toString method is implicitly called and that value is used.
          - this always works, why?
             - the Object class has a toString method defined for it
       - why does this compile even though we never specified a constructor?
          - the Java compiler implicitly defines the default constructor for you if you don't provide one!
             - it would be the same as putting in a constructor with no code in it

  • Look at intcellexamples.cpp in big3.cpp code
       - We've created 4 different IntCell variables
          - 'a' was created with the constructor
          - 'b' was created by assigning it to 'a' in the constructor statement
          - 'c' was created by pass 'a' as a parameter to the constructor
          - 'd' was created with the constructor and then assigned later on to 'a'
       - Where is the constructor used to create 'c' come from?
          - this is called the "copy constructor" and is implicitly provided by the compiler if we don't explicity define one
       - What will be the output?
          - interestingly enough, 1, 2, 3, 4!
       - What does this imply?
          - a, b, c, and d all are separate objects.
       - Is this surprising?
          - the output should not be that surprising
             - we've not declared any of these variables as pointers, so we know they're independent objects on the stack
          - the surprising thing is that this somehow works as we expect it should work

  • The C++ compiler provides two default functions for you: copy constructor and the = operator
       - copy constructor
          - the copy constructor is called for both 'b' and 'c'
             - 'c' is not surprising since it looks like a constructor
             - 'b' is just another way of writing it, but the copy constructor is still called
          - by default, the copy constructor
             - for objects: apply copy constructor calls to each of the member variables
             - for built-in types (e.g. int, double and pointers!): simple assignment is done, that is, copy the value
       - = operator
          - called when the = operator is used and the left hand side is NOT a new variable definition (that is, when we have two already constructed objects)
             - d = a
          - by default, the = operator
             - for object: apply the = operator on each of the member variables
             - for built-in type: again, simple assignment
       - default behavior
          - is intuitive: to copy an object, you simply copy all of the member variables
          - works in many situations (like our IntCell example above)

  • Look at IntCell2 class definition in big3.cpp code
       - What has changed from IntCell?
          - instead of storing the value as an int, we're storying it as int* and keeping the value on the heap
             - again, do as I say, not as I do :)
             - there are rarely situations when you would actually need/want an int pointer or storing an int on the heap, but it makes the examples simpler
          - another difference with C++, we can store built-in types on the heap! (that is, without wrapping them in an object)
          - What class does this look like in Java?
             - similar to the Integer class
       - What would happen if in intcellexamples.cpp we changed the variables to be of type IntCell rather than IntCell2?
          - we now get 4, 4, 4, 4 as a result. Why?
          - a, b, c and d still are 4 separate objects on the call-stack
          - the problem is that their private member "value" all point to the same thing. why?
             - when 'b' and 'c' are constucted the default copy constructor is called
                 - the default behavior for pointers is to copy the value over
                - this is called a "shallow" copy of the data structure
             - similarly, when we set 'd = c' the default = operator is a shallow copy

  • defining your own copy constructor and operator= methods
       - sometimes (often when your dealing with pointers, and specifically almost any time you have "new" in your code you need to override the default copy constructor and = operator
       - the copy constructor
          MyClass(const MyClass &rhs)

          - a constructor that takes an object of that type (passed by reference) and makes a copy of that variable
       - the operator=
          const MyClass& operator=(const MyClass& rhs)

          - has the special name "operator="
             - in fact, to override any operator, it's a similar format
          - takes as a parameter an object of that type (passed by reference)
          - what is the return type?
             - returns a MyClass object. Which makes sense, since we're assigning it to something that is of type MyClass
             - return-by constant reference
                - same basic idea as parameter passing
                - Java is always return-by value, that is the value being returned is copied
                - C++ has:
                   - return-by reference
                   - return-by constant reference
                - why?
                   - like call-by reference, it allows us to return objects without copying them
                - why the const?

  • look at IntCellFull class definition in big3.cpp code
       - as always, we declare the function definitions in the header file
       - copy constructor is generally easier
          - we're given an IntCellFull object and we just need to copy it
          - in this case, that just means making sure we point "value" at a new heap int location
             - rhs.value gives us the value
             - since it's a pointer, we need to dereference it with *
       - operator=
          - remember, the operator= is not a constructor. We have two pre-existing classes and we're just trying to make the current one equivalent (or equal) to the one passed in (on the right hand side of the = sign)
          - this
             - just like Java, "this" references the current object
             - in C++, this means that it is a pointer!
                IntCellFull* this
                 or in general   
                MyClass* this
             - need to use -> or * since it's a pointer to access member variables and member functions
          - the if statement is almost always there in the operator= function. What is it checking?
             - making sure we're not trying to copy ourselves
             - a = a;
          - what's pointed to by value, gets what it pointed to by the value from rhs (what we're trying to copy)
          - return *this
             - also very common

  • look at linkedlist.cpp code
       - should be similar to the code you wrote in lab
       - look at test2 in linkedlisttest.cpp
          - what did your answer print out?
             L: 9 8 7 6 5 100 3 2 1 0
             L2: 9 8 7 6 5 100 3 2 1 0
          - why?
             - because we used the default copy constructor, which does a shallow copy of the data
             - the default copy constructor would just copy the pointer value of head
             - l and l2 would refer to the same chain of Nodes
       - what if we wanted it to do a deep copy?
          - add a copy constructor that traverses the Node chain and copies it
       - look at linkedlistimproved.cpp code
          - added both the copy constructor and the = operator
             - almost always if you add one, you're going to need the other
          - look at the copy constructor... often we can reuse code
          - look at the = operator
             - clear (that is, empty) the linked list
             - copy it over a node at a time

  • look at assignment 10