CSC 324 Tutorial Week 9 ======================= Question 1 ========== Recall something close to our sum example from last week (some parts omitted): int main() { vector nums; double num; while (cin >> num) { nums.push_back(num); } cout << "Average: " << sum(nums) / nums.size() << endl; return 0; } double sum(const vector& v) { double total = 0; for (vector::const_iterator i = v.begin(); i != v.end(); ++i) { total += *i; } return total; } a) Suppose we declared nums to be: const vector nums; Would the compiler complain about: nums.push_back(num) sum(nums) nums.size() Answer: only push_back, since it changes nums b) What if num was declared: const double num; Answer: compiler would complain about cin >> num c) What could be a declaration of operator >> for cin >> num? Answer: bool operator>>(istream& i, double& d) - need to update stream information, e.g. read-ahead buffer, and double of caller d) What if sum was declared: double sum(vector& v) Answer: okay e) Why bother with const when declaring sum? Answer: If we made double average(const vector& v) { return sum(v) / v.size(); } then compiler would complain f) Would average compile if sum was declared: double sum(vector v) Answer: Yes, since vector and elements will be copied so can't affect original. g) What if sum was declared: double sum(const vector v) Answer: Still okay, uninteresting to user of sum. Question 2 ========== Recall our rational class example from last week (some parts omitted): template class Rational { public: Rational(T n) { this->n = n; d = 1; } Rational(T n, T d) { this->n = n; this->d = d; } void operator+=(const Rational& r) { n = n * r.d + r.n * d; d *= r.d; } private: T n; T d; friend ostream& operator<< (ostream& o, const Rational& r); }; template ostream& operator<<(ostream& o, const Rational& r) { o << r.n << "/" << r.d; return o; } template T sum(const vector& v) { T total(0); for (typename vector::const_iterator i = v.begin(); i != v.end(); ++i) { total += *i; } return total; } int main() { vector > rs; rs.push_back(Rational(1, 2)); rs.push_back(Rational(2, 3)); rs.push_back(Rational(-1, 6)); cout << sum(rs) << endl; return 0; } a) Write a function positive that takes a Rational and returns whether it's positive. Answer: template bool positive(const Rational& r) { return r.n * r.d > 0; } and in Rational: friend bool positive(const Rational& r); b) Write positive as a method in Rational. Answer: bool positive() { return n * d > 0; // or: return this->n * this->d > 0; } c) Where does the const go, so people with const Rationals can call it? Answer: bool positive() const { return n * d > 0; } [you could talk about the implicit this pointer given to member methods] Question 3 ========== a) What is wrong with the following: Rational& zero() { Rational r(0, 1); return r; } Answer: r is a local variable, the rational object is inside it, the variable/object goes away when zero returns, so reference points to nothing b) Why was the following okay in lecture: template ostream& operator<<(ostream& o, const Rational& r) { o << r.n << "/" << r.d << endl; return o; } Answer: user passes a reference to the object and simply gets it back. Question 4 ========== Write swap in C++ to swap the values of two variables of the same type. Answer: template swap(T& v1, T& v2) { T t = v1; v1 = v2; v2 = t; } [why would it be wrong to declare the local variable as "T& t = v1;" ?] Question 5 ========== a) How do we make objects that live longer than the function where they're created? Answer: Rational* r = new Rational(1, 2); - new: put object in the heap (In CSC 108/148/150 called the object space) - *: indicates pointer b) How do we get rid of it? Answer: unlike Java, doesn't automatically go away when unused. delete r; c) How do we access methods? r->positive() (*r).positive() d) How does const interact with pointers? void f(const Rational* crp, Rational* const rpc) { (*crp)+=(*crp); // bad: object is const (*rpc)+=(*rcp); // okay: object not const crp = crp; // okay: pointer not const rpc = rpc; // bad: pointer const } - can have both consts if desired e) What does the following do: Rational* r1 = new Rational(1, 1); Rational* r2 = new Rational(2, 1); Rational* r3 = new Rational(3, 1); f(r1, r2, r3); cout << *r1 << " " << *r2 << " " << *r3 << endl; void f(Rational* r1, Rational* r2, Rational* r3) { (*r2)=(*r3); r1 = r2; (*r1)+=(*r3); Rational r = *r1; r += Rational(4, 1); } Answer: f copies contents of third object into second local r1 and r2 point to second object pointed to by caller's r2 third object added to second local object made, copy of second local object altered output is (shown here in reduced form): 1 6 3