CS62 - Spring 2011 - Lecture 34
opening file streams with a string parameter
- ofstream fout(filename.c_str());
- ifstream fin(filenmae.c_str());
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 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 constructed 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 constant 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
destructors
- Anything wrong with doing the following in Java?
Vector v = new Vector();
v = new Vector();
- nope
- functionally everything works fine. v now points to a new Vector object on the heap
- eventually, the garbage collector will notice that the original Vector object is free and reclaim it
- when can an object be garbage collected?
- when there are no references remaining to that object
- what about in C++?
vector<int>* v = new vector<int>;
v = new vector<int>;
- functionally, everything works fine
- the problem, is that C++ is not garbage collected
- we now have a chunk of memory that we cannot access, but also cannot reuse
- in C++ we need to explicitly tell the memory manager that we're done with that memory
- the "delete" command does this:
vector<int>* v = new vector<int>;
delete v;
v = new vector<int>;
- we told the memory manager that we don't need the memory allocated to the first object
- objects can be very complicated. how does the memory manager know what memory to free up?
- the destructor: one final method that the compiler provides a default implementation for:
~MyClass()
(opposite of the constructor)
- the destructor is called when an object is no longer needed
- when the programmer explicitly calls delete on an object
- Any other times when a variable might not be needed anymore?
- when a variable's scope is disappearing
- for example, a local variable when we return from a method
- what do you think the default behavior for the destructor is?
- recursively calls delete on all of the member variables
- doesn't matter for built-in types