490 likes | 611 Views
Week 6. Lab 2 is marked Hand in Lab 3 Questions from Last Week Operator Overloading Lab 4. Schedule. Stack vs. Heap. Allocate on the stack: if (x > 0) { Rectangle r(3,4); cout << r.area(); } Object exists only while execution is between the brace brackets. Stack vs. Heap.
E N D
Week 6 • Lab 2 is marked • Hand in Lab 3 • Questions from Last Week • Operator Overloading • Lab 4 Kate Gregorywith material from Deitel and Deitel
Schedule Kate Gregorywith material from Deitel and Deitel
Stack vs. Heap • Allocate on the stack: if (x > 0) { Rectangle r(3,4); cout << r.area(); } • Object exists only while execution is between the brace brackets Kate Gregorywith material from Deitel and Deitel
Stack vs. Heap • Allocate on the heap: if (x > 0) { Rectangle* pr = new Rectangle(3,4); cout << pr->area(); } • Object continues to exist until it is deleted • If you plan to save a pointer and use it elsewhere, it must point to a location on the heap Kate Gregorywith material from Deitel and Deitel
Gets and Sets class BankAccount { private: int balance; //in pennies public: int getbalance() {return balance;} void setbalance(int bal) {balance = bal;} // other stuff }; Kate Gregorywith material from Deitel and Deitel
Encapsulation to the Rescue class BankAccount { private: float dollarbalance; //in dollars public: int getbalance() {return (int) (dollarbalance*100);} void setbalance(int bal) {dollarbalance = bal/100.0;} // other stuff }; Kate Gregorywith material from Deitel and Deitel
Overloading Revisited • When a two functions have the same name, they are overloaded class foo { public: int something(int x); int something(); }; Kate Gregorywith material from Deitel and Deitel
Operator Overloading • All languages have operator overloading int x = 1 + 1; float f = 1.0 + 1.0; • Usually, the compiler is the only one who “gets to play” Kate Gregorywith material from Deitel and Deitel
Operator Overloading • How do you compare two objects? Date d1, d2; // they get values somehow if (d1.equals(d2)) { // something } Kate Gregorywith material from Deitel and Deitel
Operator Overloading • Wouldn’t this be nicer? Date d1, d2; // they get values somehow if (d1 == d2) { // something } Kate Gregorywith material from Deitel and Deitel
Operator Overloading • How about this? Date d1, d2; // they get values somehow if (d1 != d2) { d1 = d2 + 3; } Kate Gregorywith material from Deitel and Deitel
How do you overload an operator? • You write a function • The name is operator followed by the symbol operator+ operator== Kate Gregorywith material from Deitel and Deitel
Where does the function go? • For binary operators: class A, B; A a; B b; // give them values somehow int x = a + b; Kate Gregorywith material from Deitel and Deitel
Operator Overload as Member Function // in A.h class A { // whatever else it has int operator+(B b); }; // in A.cpp int A::operator+(B b) { // something } Kate Gregorywith material from Deitel and Deitel
Operator Overload as Global Function // not in any class int operator+(A a, B b); • Typically the declaration is in the header file for A and the implementation is in the implementation file for A Kate Gregorywith material from Deitel and Deitel
Operator Overload as Global Function // in A.h class A { // whatever else it has }; int operator+(A a, B b); // in A.cpp int operator+(A a, B b) { // something } Kate Gregorywith material from Deitel and Deitel
Your class isn’t always on the left class A; A a; int x = A + 2; int y = 2 + A; • What functions does the compiler look for? Kate Gregorywith material from Deitel and Deitel
Your class on the left int x = A + 2; • A::operator+(int i) • operator+(A a, int i) • The choice is yours Kate Gregorywith material from Deitel and Deitel
Your class on the right int x = 2 + A; • int::operator+(A a) • Not possible! • operator+(int i, A a) • Your only choice Kate Gregorywith material from Deitel and Deitel
Coding a Global Operator • Sometimes it’s easy: class A { private: int x; public: int operator+(int arg); //other stuff }; int operator+(int arg, A a); Kate Gregorywith material from Deitel and Deitel
Coding a Global Operator • Here’s a neat trick int A::operator+(int arg); { return x + arg; } int operator+(int arg, A a); { return a + arg; } Kate Gregorywith material from Deitel and Deitel
Coding a Global Operator • Sometimes the operator is not reversible like that • The global function will need access to private member variables of the class it works with • It needs to be an honourary member of the class • friend Kate Gregorywith material from Deitel and Deitel
Where does the function go? • For unary operators: class U; U u1, u2; // give them values somehow u2 = !u1; Kate Gregorywith material from Deitel and Deitel
Operator Overload as Member Function // in U.h class U { // whatever else it has U operator!(); }; // in U.cpp U U::operator+() { // something } Kate Gregorywith material from Deitel and Deitel
Operator Overload as Global Function // in U.h class U { // whatever else it has }; U operator!(U u); // in U.cpp U operator!(U u) { // something } Kate Gregorywith material from Deitel and Deitel
What can you overload? • Binary + - * / % += -= *= /= %= ++ -- (pre and post) ^ & | > < >= <= == != [] Kate Gregorywith material from Deitel and Deitel
What can you overload? • Unary + - ! • Some other scary ones eg & Kate Gregorywith material from Deitel and Deitel
Operator Consistency • Operator+ should do something that feels like adding • Matrix add, complex number add • Container (list, queue) add an element • String concatenate • Increase date • Don’t mess with people’s heads Kate Gregorywith material from Deitel and Deitel
Operator Consistency • If you have defined similar operators, they should work the same way. • These three expressions should all have the same result: A a; a = a + 1; a += 1; a++; Kate Gregorywith material from Deitel and Deitel
Tip • Use one operator to implement the others: bool A::operator==(const A& arg) { // whatever } bool A::operator!=(const A& arg) { return !(*this == arg); } Kate Gregorywith material from Deitel and Deitel
More Rules • You can’t change the order of operations • You can’t invent new operators, including unary versions of binary-only operators such as /. • You can’t overload operators that work on only fundamental types: int operator+(int i, int j) Kate Gregorywith material from Deitel and Deitel
Overloading << cout << “my number is “ << 3 << endl; Employee e; cout << e << endl; • Compiler is looking for ostream& operator<<(ostream& o, Employee e) • Typically the code is just like a display() function • Return the ostream& that was passed Kate Gregorywith material from Deitel and Deitel
Simple Array Class • Implement an Array class with • Range checking • Array assignment • Arrays that know their size • Outputting entire arrays with << • Array comparisons with == and != • Element access with [] Kate Gregorywith material from Deitel and Deitel
array.h class Array { friend ostream& operator<<( ostream& o, const Array& a); public: Array( int size = 10 ); Array( const Array& a); //copy constructor ~Array(); int getSize() const { return size; } const Array& operator=( const Array& a); bool operator==( const Array& a) const; bool operator!=( const Array& right ) const { return !( *this == right ); } int& operator[]( int ); const int& operator[]( int ) const; private: int size; int* ptr; // pointer to actual content }; Kate Gregorywith material from Deitel and Deitel
Using the Array class int main() { Array integers1(7), integers2; cout << "integers1:" << integers1 << endl; cout << "integers2:" << integers2 << endl; integers1[5] = 1000; cout << integers1[5] << endl; if ( integers1 == integers2 ) cout << "They are equal\n\n"; else cout << "They are not equal\n"; return 0; } Kate Gregorywith material from Deitel and Deitel
Implementing Array - constructor Array::Array( int arraySize ) { size = ( arraySize > 0 ? arraySize : 10 ); ptr = new int[ size ]; for ( int i = 0; i < size; i++ ) ptr[ i ] = 0; } Kate Gregorywith material from Deitel and Deitel
Implementing Array - destructor Array::~Array() { delete [] ptr; } • Whenever your destructor does something destructive, you must code a copy constructor and an assignment operator Kate Gregorywith material from Deitel and Deitel
Destructive Destructors • Not all classes have a destructor that actually cleans up • Free memory • Close file • Release lock or database connection or ... • When the destructor cleans up you need to be sure it will never go off accidentally Kate Gregorywith material from Deitel and Deitel
Shallow and Deep Copies • An object holds a resource (pointer to memory, name of file, pointer to connection object) • If you copy the object bit-for-bit, now two objects hold the same pointer (or handle or name or whatever) • When one goes out of scope, the destructor cleans up • The other has a pointer to nowhere! Kate Gregorywith material from Deitel and Deitel
Implementing Array – copy constructor Array::Array( const Array& init ) : size( init.size ), ptr(new int[init.size]) { for ( int i = 0; i < size; i++ ) ptr[i] = init.ptr[i]; } Kate Gregorywith material from Deitel and Deitel
Copy Constructor takes a reference • Imagine this code: Array a2(a1); • This uses the copy constructor to construct a2 • Takes by value: need to make a copy of a1 to pass to the function • Use the copy constructor. • But that takes by value, so need to make a copy • Use the copy constructor • . . . Kate Gregorywith material from Deitel and Deitel
Implementing Array – assignment operator const Array& Array::operator=( const Array right ) { // always check for self-assignment if ( &right != this ) { if ( size != right.size ) { delete [] ptr; size = right.size; ptr = new int[ size ]; } for ( int i = 0; i < size; i++ ) ptr[ i ] = right.ptr[ i ]; } return *this; // enables x = y = z; } Kate Gregorywith material from Deitel and Deitel
Copy Constructor vs Assignment operator • It’s not about whether the = operator is used • It’s about whether something is being constructed Array a1(10); Array a2(a1); Array a3 = a2; a1 = a3; Kate Gregorywith material from Deitel and Deitel
Implementing Array – equality test bool Array::operator==( const Array& right ) const { if ( size != right.size ) return false; // arrays of different sizes for ( int i = 0; i < size; i++ ) if ( ptr[ i ] != right.ptr[ i ] ) return false; // arrays are not equal return true; // arrays are equal } Kate Gregorywith material from Deitel and Deitel
Implementing Array – element access int& Array::operator[]( int subscript ) { if( subscript >= 0 && subscript < size ); return ptr[ subscript ]; else // should throw exception or something exit(1); } • Why does it return a reference? integers1[5] = 1000; Kate Gregorywith material from Deitel and Deitel
Implementing Array const int& Array::operator[]( int subscript ) const { if( subscript >= 0 && subscript < size ); return ptr[ subscript ]; // const reference else // should throw exception or something exit(1); } • For use with const arrays (since it’s const) • Guarantees the object will stay const by not providing a reference to the inside, which could be changed. Kate Gregorywith material from Deitel and Deitel
Implementing Array ostream& operator<<( ostream& output, const Array& a ) { int i; for ( i = 0; i < a.size; i++ ) { output << a.ptr[i] << endl; } return output; //enables cout << x << y; } Kate Gregorywith material from Deitel and Deitel
Remember The Requirements • Implement an Array class with • Range checking • Array assignment • Arrays that know their size • Outputting entire arrays with << • Array comparisons with == and != • Element access with [] Kate Gregorywith material from Deitel and Deitel
For Next class • Enjoy Reading Week – see you Feb 24 • Read chapter 9 • Do Lab 4 • Study for Midterm • Feb 24, class time, this room • Will cover everything till today • You may be asked to write code in handwriting • One hour, closed book • Worth 25% Kate Gregorywith material from Deitel and Deitel