/* Move the definition of the speak method from class Dog outside of the class, and get the result to compile. Try declaring a variable of type Pet. As described in the lectures, this is not allowed: see if you can make sense of the error message the compiler gives. Try redefining the speak method in class Dalmatian, and verify that your new version works. If you copy a Dalmatian object into a Dog object, what version of speak does the resulting object have? Declare a vector of pointers to Pets and add some pointers to it (using either & or new). Loop over the vector calling speak on each pet. Repeat the previous question, this time using a list instead of a vector, and using an iterator to traverse the list. */ #include #include #include #include #include using namespace std; class Pet { protected: string _name; public: Pet(string name) : _name(name) {} virtual string sound() const = 0; virtual void speak() const { cout << _name << ": " << sound() << "!\n"; } }; class Dog : public Pet { public: Dog(string name) : Pet(name) {} virtual string sound() const { return "woof"; } virtual void speak() const ; }; void Dog::speak() const { Pet::speak(); cout << '(' << _name << " wags tail)\n"; } class Dalmatian : public Dog { int _spots; public: Dalmatian(string name, int spots) : Dog(name), _spots(spots) {} void speak() const override { Dog::speak(); cout << "(I've got " << _spots << " spots)\n"; } }; class Cat : public Pet { public: Cat(string name) : Pet(name) {} virtual string sound() const { return "miao"; } }; void speakTwice(const Pet &pet) { pet.speak(); pet.speak(); } int main() { // Pet pet("Fido"); ERROR - Pet is abstract Dog d("doggo"); Dalmatian da("fido", 101); cout << "\tDog's speak\n"; d.speak(); cout << "\tDalmatian's speak\n"; da.speak(); // d = da; cout << "\tDalmatian's speak\n"; d.speak(); cout << "\tDalmatian's speak\n"; da.speak(); Dog & dogref = da; cout << "\tDalmatian's speak?\n"; dogref.speak(); vector vp; vp.push_back(&d); vp.push_back(&da); Cat c("Tom"); vp.push_back(&c); cout << "\tWith vector\n"; int count = 0; for (const auto &pet : vp) { ++count; // pet.speak(); // ERROR - pet (vp element) is a POINTER to a Pet! pet->speak(); } cout << "\t\tCounted " << count << " times\n"; list lp(begin(vp), end(vp)); cout << "\tWith list\n"; // for (list::iterator it = begin(lp), eit = end(lp); it != eit; ++it) { for (auto it = begin(lp), eit = end(lp); it != eit; ++it) { // it->speak(); // ERROR - "it" points to an element, which // is a pointer. So we need to dereference the // iterator "it" to get the pointer: (*it)->speak(); // (**it).speak(); } cout << "\tWith for_each\n"; count = 0; /* * Algorithms like for_each use (1) a pair (range) of iterators, and (2) * a lambda (anonymous) function. * * Lambda functions: their name is "[]"; their parameter is the same as * in a range-for loop (for most algorithms), in the sense that they are * called with elements of the container; their body is like that of the * range-for. * * If you need to access variables defined outside the lambda function, * then you need to *capture* them - either by value (the outside code * will not see any modifications to them), or by reference, like count * below. Captured variables are placed in between the []'s. * * See https://en.cppreference.com/w/cpp/language/lambda for more. */ for_each(++begin(lp), --end(lp), [ &count ] (const auto &pet){ ++count; pet->speak(); } ); cout << "\t\tCounted " << count << " times\n"; return 0; }