def do_it_twice(x) x.doit x.doit endQuestion: how do we find the code to execute for doit?
long fact(int n) { return n <= 0 ? 1 : n * fact(n - 1); } long pow2(int n) { return n <= 0 ? 1 : 2 * pow2(n - 1); } long (number_cruncher*)(int); if ( x > 0 ) number_cruncher = pow2; else number_cruncher = fact; cout << (*number_cruncher)(x); // either pow2(x) or fact(x)
class X { public: void a(); virtual void b(); virtual void c(); }; class Y : public X { public: void b() override; void d(); virtual void e(); };
X *something = new X(), *other = new Y();
+-------------------+ | &X::b | &X::c | +-------------------+
+-----------------------------+ | &Y::b | &X::c | &Y::e | +-----------------------------+
Y *confused = new X();isn't just a "little" illegal!!
class SList { class SNode { // can nest classes; note this is private public: string item; SNode *next; SNode(string it, SNode *n = nullptr) // default value : item{it}, next{n} { } } *front, *tail; // note * applies only to next item public: SList() { front = tail = nullptr; } ~SList() { clear(); } bool empty() const { return front == nullptr; } void push_front(string x) { if ( front ) front = new SNode(x, front); else { front = tail = new SNode(x); } } void push_back(string x) { if ( empty() ) push_front(x); else { tail->next = new SNode(x); tail = tail->next; } } string take_front() { if ( empty() ) throw "error: no first element of empty list"; string result = front->item; SNode *tmp = front->next; delete front; front = tmp; if ( empty() ) tail = nullptr; return result; } void clear() { while ( !empty() ) take_front(); } };What happens when we execute
SList a; a.push_back("laura"); a.push_back("paul"); if ( !a.empty() ) { SList b; b = a; a.push_back("zebra"); ... code using b ... }
void SList::setTo(const SList &other); // create a copy of other
void print(SList list_copy) // note get a copy! { while ( !it.empty() ) cout << it.take_front() << endl; } ... print(a);
SList double(const SList& input) { SList result = input; result += input; return result; }
public: ... SList(const SList &other);
SList& operator=(const SList &other) { if ( this != &other ) { clear(); setTo(other); } return *this; }
SList a, b, c; ... a = b = c; (a = b).push_back("why?");
class Base { ... public: ~Base(); }; class Derived : public Base { ... public: ~Derived(); }; Derived *one = new Derived; Base *two = new Derived;Derived::~Derived is executed for
delete one;but not for
delete two;Potential memory leak!
class Event { Ticket *tickets[NUM_SEATS]; int sold; public: ... ~Event() { for(int i = 0; i < sold; ++i) delete tickets[i]; } ... }; class Concert : public Event { Reservation *venue; public: ~Concert() { delete venue; } };with
Event *nextWeek = new Concert; ... delete nextWeek; // executes Event::~Event, not Concert::~Concert
class Base { ... public: virtual ~Base(); };and
virtual ~Event() { for(int i = 0; i < sold; ++i) delete tickets[i]; }Generally, compilers will issue warnings, but you have to know why it's necessary.
SList a, b, c; ... c = a + b;
SList(SList&& src); // move constructor SList& operator=(SList&& src); // move assignment
SList::Slist(SList&& src) : front{src.front}, tail{src.tail} { src.front = src.tail = nullptr; }
SList& operator=(SList &&src) { if ( this != &src ) { clear(); front = src.front; tail = src.tail; src.front = src.tail = nullptr; } return *this; }
class X { ... other stuff ... public: X(const X&) =delete; const X& operator=(const X&) =delete; X(X&&) =delete; void operator=(X&&) =delete; };
char initials[4] = "XYZ";
cin >> initials;What would happen if someone entered 4 characters?
int strlen(const char str[]) { int len = 0; char* p = str; while ( *p != '\0' ) { ++len; ++p; } return len; }
#include <string> using namespace std; string name, ghost = "Casper"; cin >> name; // reads one word if ( name == "Waldo" ) cout << "Found him!" << endl; else if ( name == ghost ) cout << "I'm outta here!" << endl;
class string { public: bool operator==(string other) const { // just one argument! if ( this == &other ) return true; // do charwise comparison } bool operator==(const char* other) const { return *this == string(other); // call above method } // ... rest of class }
if ( "name" == ghost ) // never legal
cout << "howdy " + 42;fails. It's actually the same as writing
cout << "howdy"[42];Not useful.
ghost.c_str()
int* f() { int nums[100]; int mult_of_ten = 0; for(int i = 0; i < 100; ++i, mult_of_ten += 10) nums[i] = mult_of_ten; return nums; ... // just as dangerous: return &mult_of_ten; }