I'm confused about polymorphism in C++. I'm studying it by myself, and I understood its main features. But I don't understand why it is helpful. Before studying polymorphism (about oop), I studied inheritance (that is helpful, because you can use a method in the superclass and subclass writing just only once). Now I'm stuck with polymorphism and the virtual keyword. I don't understand why it is helpful. See the code below (it's an exercise about C++ institute (I will get a certification)). Why can I declare as "virtual" only functions? I add in the code the variables n1, n2, n3 (as public), why cant I access them? I don't understand at all polymorphism, I read tons of posts about polymorphism on StackOverflow, but it's as if I understood polymorphism at 50%. I noticed that polymorphism is less difficult to understand in python because python doesn't have data types, but I want to understand it in C++ also, and its possible uses.
#include <iostream>
using namespace std;
class Pet {
protected:
string Name;
public:
Pet(string n) { Name = n; }
virtual void MakeSound(void) { cout << Name << " the Pet says: Shh! Shh!" << endl; }
int n1;
};
class Cat : public Pet {
public:
Cat(string n) : Pet(n) { }
void MakeSound(void) { cout << Name << " the Cat says: Meow! Meow!" << endl; }
int n2;
};
class Dog : public Pet {
public:
Dog(string n) : Pet(n) { }
void MakeSound(void) { cout << Name << " the Dog says: Woof! Woof!" << endl; }
int n3;
};
int main(void) {
Pet* a_pet1, * a_pet2;
Cat* a_cat;
Dog* a_dog;
a_pet1 = a_cat = new Cat("Kitty");
a_pet2 = a_dog = new Dog("Doggie");
a_pet1->MakeSound();
a_cat->MakeSound();
static_cast<Pet*>(a_cat)->MakeSound();
a_pet2->MakeSound();
a_dog->MakeSound();
static_cast<Pet*>(a_dog)->MakeSound();
}
Perhaps an example can help. Consider a different main(), like this:
int main()
{
std::vector<std::unique_ptr<Pet>> menagerie;
menagerie.push_back(std::make_unique<Dog>("Fido"));
menagerie.push_back(std::make_unique<Cat>("Morris"));
menagerie.push_back(std::make_unique<Cat>("Garfield"));
menagerie.push_back(std::make_unique<Dog>("Rover"));
for (auto&& pet : menagerie)
{
pet->MakeSound();
}
}
Here we have a bunch of pets. We can handle them all the same way, but they make different sounds. Calling MakeSound on each does the right thing for that particular kind of pet. This sort of use case is very common.
Fido the Dog says: Woof! Woof!
Morris the Cat says: Meow! Meow!
Garfield the Cat says: Meow! Meow!
Rover the Dog says: Woof! Woof!
Now, try removing the virtual keyword and they'll all say "Shh! Shh!".
You are right, it's not easy to understand how polymorphism is useful and what it does when learning it. The common examples like you referred doesn't really help which merely demonstrates the concept but lacks real context.
The understanding and be able to use polymorphism is rather advance topic in programming. It is employed when following truly object oriented programming like SOLID and design patterns.
A good real world example of poloymophism in action is iterator design pattern. You define a base class say of a list with method like next(), then you can have different derived classes (for different kind of lists) all overriding this method and they implement it so you are able to iterate that list accordingly.
As you might be seeing it gets complicated so I can't explain everything here but you get an idea and some pointers.
The key idea of polymorphism is to have one method. This method will have different implementations, and a particular implementation is called based on certain situations.
Let's consider this example:
#include <iostream>
using namespace std;
class Polygon{
protected:
int numVertices;
float *xCoord, *yCoord;
public:
void set(){
cout<<"From Polygon"<< endl;
}
};
class Rectangle : public Polygon{
public:
void set(){
cout<<"From Rectangle"<< endl;
}
class Triangle : public Polygon{
public:
void set(){
cout<<"From Triangle"<< endl;
}
};
int main(){
Polygon *poly;
Rectangle rec;
Triangle tri;
poly = &rec;
poly->set();
poly = &tri;
poly->set();
}
When you run this code your output is the following:
From Polygon
From Polygon
Let's add virtual to set() in base class (Polygon) . Here is what you get:
From Rectangle
From Triangle
If we have created a virtual function in the base class (Polygon) and it is being overridden in the derived class (In this case, Triangle and Rectangle) then we don’t need virtual keyword in the derived class, functions are automatically considered as virtual functions in the derived class.
The idea is set() will call the base class version of the method if set() is not virtual even if poly is pointed to Rect.
On the other hand, set() that is virtual, it will call the actual method from the derived class. (In this case, rect->set() will print "From Rectangle").
Doing this means that in situations where I don't know the particular type of an object, I can use virtual and polymorphism and it will use the correct method during a call.
I hope this helps!
Related
I want to have a parent class which it stores all child class and the child class can have a derived classes which each classes is unique.
that's why I want to initialize class in a function but a class is a parameter. I don't know what to describe but let's look at the code.
I'm beginner btw.
class Child {
string child_name;
}
class Jame : public Child {
void sit() {
cout << "Jame can sit" << endl;
}
}
class Harry : public Child {
void sleep() {
cout << "Harry can stand" << endl;
}
}
class Parent {
vector <Child> children;
void addChild(string class_name) { //Prototype
[classname] child; //EX. Jame child;
child.child_name = class_name;
children.push_back(child);
}
Child* getChild(string child_name) {
for(int i = 0; i < children.size(); i++)
if(children.at(i).child_name == child_name)
return &children.at(i);
}
};
int main() {
Parent parent;
parent.addChild("Harry");
Child* child = parent.getChildren("Harry");
child->sleep(); //Harry can stand.
child->sit(); //error: undefined function.
return 0;
}
Something like this.
If you have any other ways help me please, I'm very new and I don't know what it's called.
As I understand, there is really two questions here:
How to get addChild("Harry") to find the right child class and register it.
How to have certain functions which only work for particular child classes.
Number one is a fairly standard factory/registrar class, which might be good to read up on (here, but you can find other resources online). Maybe you could do something like this:
class Parent {
// This needs to be unique_ptr<Child>!
std::map<std::string, std::unqiue_ptr<Child>> children;
template<typename ChildType>
void addChild(string class_name) {
// Make sure ChildType is derived from Child
static_assert(std::is_base_of<Child, ChildType>::value);
children[class_name](std::make_unique<ChildType>());
}
...
}
int main() {
Parent parent;
// You'll need to give it the actual child type here
parent.addChild<Harry>("Harry");
...
}
As for number two... there isn't really a way to get that to work with polymorphism like you'd want. Depending on how you're using this class, dynamic_cast might be worth trying:
Child* child = parent.getChildren("Harry");
if (Harry* harry = dynamic_cast<Harry*>(child)) {
harry->sleep();
} else if (Jame* jame = dynamic_cast<Jame*>(child)) {
jame->sit();
}
It seems to me that you are misinterpreting something, or at least the way you implement this is very weird. It seems as if you want to have Harry and Jame as instances of Child and not actually a derived class of Child. The reason why I say this is, because Harry and Jame do not seem to be designed as classes, but as interfaces to controlling one instance of a single class. A better way of handling this is that when you define Child you could do it like:
class Child{
private:
bool canSleep;
bool canSit;
std::string name;
public:
Child(std::string _name,bool sleep, bool sit)
: name(_name), canSleep(sleep), canSit(sit) {}
void sit(){
if(canSit) std::cout << name << " can sit\n";
}
void sleep(){
if(canSleep) std::cout << name << " can sleep\n";
}
};
You could also extend this with enums implementing flags instead of booleans, but that just helps with usability.
As for the actual question and one solution (and some issues with the code):
There is no syntax (as far as I'm aware) that would allow you to do this, the way presented here, but you can use templates. If you can use C++20 you can even constrain it easily so bad calls are caught compile time, and also produce way less noise. You can make AddChild into a template like:
// Only for c++20
#include <concepts>
class Parent {
private:
std::vector<Child*> children;
public:
template<typename Child_type>
requires std::derived_from<Child_type,Child> // Only for C++20
void addChild(std::string name){
children.push_back(new Child_type(name));
}
};
Now this is a very basic solution and can be called by parent.addChild<Harry>("Harry"); for example.
There are however other issues that I somewhat tried to mitigate. Firstly in a class every member you declare is private by default, meaning that no one outside the class (apart from friend functions, which would be a really hacky solution in this case), can access those members (including functions).
You also can't really store Harry, where a Child should go. You can store a pointer to Harry where a pointer to a Child should go however. I used raw pointers (which you should generally avoid), but you should look up std::unique_ptr and std::shared_ptr, as raw pointers are a pain.
You would also need to define sit and sleep as virtual functions to be able to reference them from a pointer to a Child (without casting to the derived types, which can be problematic if not done properly (edit: see other answer for doing it properly with dynamic_cast)).
Finally it seems you are using using namespace std;, so obligatory: It's bad practice and can lead to very difficult to debug issues.
I'm trying to have a vector of different subclass pointers that have a common base class. The vector is set to the base class pointer but anything that is added to the vector doesn't get the full functionality of the subclass it is.
It can be seen in the error log it is being treated as a base class so not getting the extended functionality.
I've looked on loads of questions and people are saying to do it the way I am doing it, but for whatever reason, it's not working.
The code is on a public repo.it:
https://repl.it/#cubingminer8/inheritance-with-vectors-testing
Any help would be greatly appreciated!
edit: ok so I'm going to use this for a sprite group system in a c++ sdl2 game engine. There will be a base sprite class that has some basic things like render and move, while any sprites I need will be their own classes that inherit from Sprite, they will have their own unique behaviors so virtual functions would be impractical. There will be a sprite group object, that objects that inherit from Sprite can be stored in. So they can all be rendered at once and such.
If you have ever used pygame then it is almost identical to the sprite and spritegroup system used there.
https://www.pygame.org/docs/tut/SpriteIntro.html
#include <iostream>
#include <vector>
class Base {
public:
char A = 'A';
};
class Sub : public Base {
public:
char B = 'B';
};
class Sub2 : public Base {
public:
char C = 'C';
};
int main() {
std::vector<Base*> List;
List.push_back(new Sub());
List.push_back(new Sub2());
std::cout << List[0]->B << std::endl; // it should be able to print B
std::cout << List[1]->C << std::endl; // but it is being set as a base class and
// not getting the functionality of the subclass it is.
}
Usually, this is achieved by virtual functions. In the given case it should be a virtual getter function which returns the char members of each class.
class Base {
char A = 'A';
public:
virtual char getChar()const /*noexcept*/ { return A; }
virtual Base () = default;
};
class Sub : public Base {
char B = 'B';
public:
char getChar()const /*noexcept*/ override { return B; }
};
class Sub2 : public Base {
char C = 'C';
public:
char getChar()const /*noexcept*/ override { return C; }
};
now in the main
std::cout << List[0]->getChar() << std::endl;
As a side note, I suggest you to have a look at smart pointers, instead of the row pointers, by which you can avoid manual memory management.
A good starting would be:
#include <memory>
std::vector<std::unique_ptr<Base>> List;
List.emplace_back(std::make_unique<Sub>());
So you want this to work:
// your code version 1
std::cout<< List[0]->B << std::endl; //it should be able to print B
std::cout<< List[1]->C << std::endl; //but it is being set as a base class
But what should happen if you write this instead?
// your code version 2
std::cout<< List[0]->C << std::endl;
std::cout<< List[1]->B << std::endl;
List[0] doesn't have any C and List[1] doesn't have any B. How do you propose to treat this code?
There are several ways to approach this.
The compiler should know at compilation time that version 1 is right, and version 2 is wrong. Unfortuantely this is generally impossible because the compiler cannot keep track of what object pointer goes to which slot in the array. So this has to be dismissed.
The run time system should detect the error at run time. This is a possible approach, but not one taken by C++. C++ is a statically typed language. Dynamically typed languages can handle this case. If you want a dynamically typed language, try e.g. Python.
The compiler should not try to detect anything, and the runtime system should not try to detect anything either, but go ahead and perforrm the operation anyway, and let it produce wrong results or crash. This is also a possible approach, but not one taken by any modern high-level programming language. C++ and other modern languages are typed. It is possible to circumvent the type system of C++ by using reinterpret_cast and the like, but this is very dangerous and is not recommended.
The compiler should treat both versions as wrong. This is what C++ does.
As others have mentioned, the (only) right way to extend functionality of a class is via virtual functions. This requires some planning ahead. The base should at least declare which operations are needed, though it doesn't need to know how derived classes will implement them.
this involves some pretty tricky inheritance, but bear with me here.
My question isn't so much a specific error, but just "how would i do this specifically?"
the idea is to have an abstract base class Food (note that this are all oversimplified for the question)
//parent of Animal
//parent of Plant
//~Food()
//Food()
#pragma once
class Food
{
public:
Food(){}
~Food(){}
};
from that comes class animal and plants. i'm not too worried about plant right now
Animal needs to have the virtual functions Hunt and Eat
#pragma once
#include "Food.h"
class Animal : public Food
{
//eat() which accepts a Food* type as an argument. it is an abstract virtual in this class, it has the form
//bool eat(Food* food)
//hunt() which accepts an stl list of Food* pointers to Food type objects. the food list is declared globally in main and passed here. it has the form
//hunt(list<Food*> &foodlist)
};
from that comes many more classes; Herbivore, Carnivore, Omnivore (which inherits from carnivore and herbivore). this is herbivore
//Child of Animal
//Parent of Lemur, Koala, Squirrel, Omnivore
//~Herbivore()
//hunt(list<Food*&foodList):bool (only eats plant types)
#pragma once
#include "Animal.h"
#include <iostream>
#include <string>
#include <list>
using namespace std;
class Herbivore : public virtual Animal
{
public:
Herbivore() {}
~Herbivore(){}
//eat() and hunt() are probably virtual here as well, as they aren't used directly, only the lower classes directly access them
};
and from those are the bottom most child classes, and they all have roughly this form. this is a Squirrel
//child of Herbivore
//leaf node
#pragma once
#include "Animal.h"
#include "Herbivore.h"
class Squirrel : public Herbivore
{
//bool eat() is fully defined here instead of being virtual.
//bool hunt() is fully defined here instead of being a virtual.
//both have the same argument lists as the virtuals in Animal
};
and here's main
list<Food*> Food_list; //global list of Food items that will be passed to hunt()
int main()
{
list<Food*>::iterator it = Food_list.begin();
(*it)->eat(*it); //passing the iterator to itself as a test. this seems to work ok
(*it)->hunt(Food_list); //however this, in my code, refuses to work for a few reasons
};
so basically everything inherits from food...but this is a bad thing.
i've tried several things with the following problems
i tried the initial version of the virtual functions in Animal, and nothing in food, it complained that Food has no function hunt
error C2039: 'hunt' : is not a member of 'Food'
....which is fair i suppose, although shouldn't it be looking at the Squirrel and not the food class?
i tried making a pure virtual in Food for eat and hunt, and from that point on, every attempt to instantiate any kind of leaf class (like a squirrel or tiger or whatever) returned the 'cannot instantiate abstract class' error.
error C2259: 'Squirrel' : cannot instantiate abstract class
i tried making the eat and hunt in food less abstract, like hunt(list &foodlist), but then it says "syntax error, identifier 'list' ", like it doesn't know what a list is....even after i include in Food.h
error C2061: syntax error : identifier 'list'
and all of these errors are paired with the error "'Food::hunt': function does not take 1 arguments"
error C2660: 'Food::hunt' : function does not take 1 arguments
my overall question is, how would you transpose this abstract virtual function from Animal to its leaf classes? and how exactly would you call it? basically everything i have tried as failed miserably
*don't worry about what's inside eat() or hunt(), i'm just looking for proper declaration*
this github for the project is also available here
https://github.com/joekitch/OOP_JK_Assignment_4
if that is desired
The solution i found involves dynamic casting.
basically, you need to cast the iterator pointer DOWN from a Food* type to something lower like an Herbivore or Animal type, either way the type must have the function you want fully defined within it
Herbivore* temp = dynamic_cast<Herbivore*>(*it)
if ( temp ){
cout << "iterator thing is a Herbivore " << endl;
temp->hunt(Food_list);
cout << "iterator thing is of the type " << typeid(temp).name() << endl;}
else cout << "iterator is not a Herbivore " << endl;}
the above code will attempt to cast it to an Herbivore type. if it's successful (that is, it's parent class is Herbivore), then Temp will be cast to the Herbivore type specified on the left. if it fails, temp will be a NULL type. this temp pointer points to the same thing as the it pointer....but it's simply treated as an Herbivore instead of a Food*.
Some thoughts,
I'm assuming Herbivore is defined somewhere...
Use virtual destructors
When something tells you it can't be instantiated SOMEWHERE a Food(), Animal() constructor is being called.
Example code:
class Food
{
public:
Food(){ }
virtual ~Food(){ }
};
class Animal : public Food
{
Animal() : Food() { }
virtual Animal() { } //Cause C++
virtual bool eat(Food* food) = 0;
virtual hunt(list<Food*> &foodlist) = 0;
};
class Squirrel : public Herbivore
{
Squirrel() : Herbivore() { }
~Squirrel() { } //not virtual
bool eat(Food *food) { //stuff };
void hunt(list<Food *> &foodlist) { //stuff };
};
list<Animal*> animal_list; //global list of Food items that will be passed to hunt()
int main()
{
animal_list.push_back(new Squirrel()); // Make sure you fill the array?
list<Food*>::iterator it = Food_list.begin();
(*it)->eat(*it); //passing the iterator to itself as a test. this seems to work ok
(*it)->hunt(animal_list); //however this, in my code, refuses to work for a few reasons
};
I have an assignment in uni to do, basically, we take in a bunch of data from many txt files. the data is structured in a way that it can be read, for this question ill cut it down to two files and two classes. an example of the data is this:
Faculty.txt ( PK, Name)
AT Advanced Technology
HESAS Health, Sport and Science
Department.txt (PK, Name, FK)
ET Engineering and Technology AT
BE Built Environment AT
CMS Computing and Mathematical Sciences AT
SAS Science and Sport HESAS
CS Care Sciences HESAS
PESD Professional Education and Service Delivery HESAS
The idea is to create report's using the data, the program is meant to use link lists, relationships and virtual functions. So in the code we basically have a list (im using FILO) of nodes-
-Out of context question-
(im not sure im getting the lectures provided node and list code concept we have been given - I say this because I cannot get my head around where node stores the memory address of the object. Unless im misunderstanding it and node is a child of each class it extends so it inherits everything from that class and add's its stuff on top? if that is the case why do we need to make a virtual function in the 1st place if we inherit all of the functionality - security?)
-that have pointers of objects stored inside them. now where im actually stuck is loading the data in - well iv loaded it all into lists fine, but i have only loaded the Foreign key's in as strings where as i need to basically check the string FK against the PK of the objects stored in the previous file iv loaded (the lecture went easy and gave us a easy 1-8 flow where 1 has no FK:)) and then when i find that object get its memory address and use that as the FK. the idea behind this is you can basically go std::cout << departmentObj->getForeignKey()->getIdentifier(); ill post some code from my test project (chopped down for testing) at this point since im not sure if im making any seance.
-- sorry guys the code block here is bugging, so it will have to be paste bin.
List.cpp
http://pastebin.com/Le3fz5YF
List.h
http://pastebin.com/5yJYDM8N
Node.cpp
http://pastebin.com/Pgas8eju
Node.h
http://pastebin.com/TZPrEA4Q
Fac.cpp
http://pastebin.com/0EGeGhdq
dep.cpp
http://pastebin.com/G2yk6jCg
Main.cpp
http://pastebin.com/npiCC6wX
refrence loader
http://pastebin.com/n6UdsYmW
so basically it comes down to returning the memory address of an desired object through the list. clearly im not getting how to access the node and list class correctly to do this. the way i would like to be able to do this is just simply have a nice line of code that i can use to replace the addnode lines in my loader (ill post that for reference) it would look like this:
departmentList->AddNode(new Department(holder[0], holder[1], facultyList->getPkObjAdd(holder[2])));
but ofc the problem lies with how to return that objects memory address. if it has to be a virtual function, how do i allow it to return multiple object types like faculty and department?
im not sure if im making much seance, i hope someone can help me out.
Thanks for your time!!
- quick edit, forgot dep and fac.cpp's
Have you included all of your code? It looks like you're missing some files (Fac.cpp includes Fac.h, but you don't seem to have posted that).
In any case, unless you've subclassed your Node class, there's no inheritance going on with that class: Node doesn't extend anything, and (as far as I could tell) nothing extends Node. Also, the way you've written it, Node contains a pointer to another Node, but no other data. If you changed the Node.h header so that it looked like:
#pragma once
#include <iostream>
#include "string"
using namespace std;
class Node
{
public:
Node();
Node(Node* next);
~Node(void);
// Member Functions
Node* GetNextNode();
void SetNextNode(Node* next);
void * GetData();
void SetData(void* data);
// Virtual Functions
virtual void DisplayContents() = 0;
virtual string getIdentifier() = 0;
virtual PROBLEM getMe() = 0;
private:
Node* nextNode;
void* data;
};
Then added the functions GetData and SetData:
void SetData(void *data)
{
this.data = data;
}
void * GetData()
{
return this.data;
}
You would then be able to store something in each Node. You probably don't want data's type to be void*, you probably want to store strings. But the idea is the same.
As for virtual functions, the idea has purely to do with inheritance. The idea with virtual functions is that an object will always call its own version of a function, rather than its parent class's version. So if you have:
class Base
{
public:
virtual void virtualFunc();
void otherFunc();
};
class Derived : public Base
{
public:
virtual void virtualFunc();
void otherFunc();
};
I'll define these functions like so:
#include "inheritance.h"
#include <iostream>
using namespace std;
void Base::virtualFunc()
{
cout << "in Base::virtualFunc" << endl;
}
void Base::otherFunc()
{
cout << "in Base::otherFunc" << endl;
}
void Derived::virtualFunc()
{
cout << "in Derived::virtualFunc" << endl;
}
void Derived::otherFunc()
{
cout << "in Derived::otherFunc" << endl;
}
Then you create some objects somewhere:
Derived *derived1 = new Derived();
Base *derived2 = new Derived();
If you call virtualFunc() on derived1 or on derived2 it will always call the copy defined in Derived, because it's declared virtual. If you call otherFunc() with derived1, it will call the version defined in Derived, because derived1 is declared as type Derived. However, derived2 is declared as Base, so if you call its otherFunc(), the copy defined in Base will be called instead. So if you have the following code:
#include "inheritance.h"
#include <iostream>
using namespace std;
int main()
{
Derived *derived1 = new Derived;
Base *derived2 = new Derived;
cout << "calling virtualFunc() with derived1: ";
derived1->virtualFunc();
cout << "calling virtualFunc() with derived2: ";
derived2->virtualFunc();
cout << "calling otherFunc() with derived1: ";
derived1->otherFunc();
cout << "calling otherFunc() with derived2: ";
derived2->otherFunc();
delete derived1;
delete derived2;
}
You'll get this as output:
calling virtualFunc() with derived1: in Derived::virtualFunc
calling virtualFunc() with derived2: in Derived::virtualFunc
calling otherFunc() with derived1: in Derived::otherFunc
calling otherFunc() with derived2: in Base::otherFunc
In your Node class, you define some pure virtual functions, which are a special. These are set to 0 in the class definition, and the idea is that in your base class (in this case, Node), you can't define their functionality. Instead, you're saying that any derived classes MUST define functionality for these functions. Note that you can't directly create objects of a class with pure virtual functions. If you have a derived class that doesn't define these functions, you won't be able to directly create objects of that type, either, you'll need to subclass it somehow in order to do that.
I'm guessing that for this assignment you're supposed to subclass Node in a few different ways in order to store different types of data in different types of nodes.
Hope this helps!
Hey thought id pop back and post the solution incase anyone wonders in future. since im handling data types where i know the return value i decided to use:
void* getMe();
void* as you may or may not know is apointer to mem address. you can then convert it using
(Faculty*)facultyList->getPkMemAdd("PK");
hope it helps someone!!
My assignment is
"My dog, named Buddy, lives in the backyard. He barks at night when he sees a cat or a squirrel that has come to visit. If he sees a frog, and he is hungry, he eats it. If he sees a frog and he isn't hungry, he plays with it. If he has eaten 2 frogs already, and is still hungry, he will let it go. If he sees a coyote, he crys for help. Sometime his friend Spot stops by, and they chase each other. If he sees any other animal, he simply watches it.
Write one test program and a set of classes that keeps track of all of the backyard activity and stores the results into a file for a given night. I would expect that you would have an animal class, and a cat, dog, squirrel, coyote class that inherits from the animal class. You would need to keep track of how many frogs he has eaten, how many animals of each type has come and visited, how often he has played and other such details. "
You will also need to write a test program that will read the file that was generated from the other test program, and print out how many animals of each type that he has seen, what he has done with them on a particular day. The user will need to enter in the date, and the information from the file for that date will be read in, and displayed.
Add in any other capability to the program that you need so it covers all of the required programming concepts listed. Be creative with this assignment.
-We are to use classes, data abstraction, inheritance, composition, pointers, operator overloading, and exception handling.-
#include <iostream>
#include <cstdlib>
using namespace std;
class animal{
public:
animal();
~animal();
void interactWithBuddy();
virtual int ID()
{
return ID;
}
};
class frog: public animal
{
public:
void interactWithBuddy();
void eat();
void play();
void letGo();
};
class dog: public animal
{
public:
void interactWithBuddy();
void chase();
};
class cat: public animal
{
public:
void interactWithBuddy();
void bark();
};
class coyote: public animal
{
public:
void interactWithBuddy();
void cryForHelp();
};
class squirrel: public animal
{
public:
void interactWithBuddy();
void bark();
};
class otherAnimal: public animal
{
public:
void interactWithBuddy();
void watch();
};
int main ()
{
srand(time(0));
int number;
std::cout << (rand() % 6 + 1) <<std::endl;
animal * a = new frog();
int z = a->ID();
animal * b = new dog();
int y = a->ID();
animal * c = new cat();
int x = a->ID();
animal * d = new coyote();
int w = a->ID();
animal * e = new squirrel();
int v = a->ID();
animal * f = new otherAnimal();
int u = a->ID();
return 0;
}
I know the code is just a shell but am I on the right track? How would you suggest counting the frogs and figuring whether they get eaten, played with, or let go? Also I want to assign each animal subclass a number in which I can then randomize in the main function so as to correlate with the assignment but I am unsure as to how that would be done. Tips and pointers would be greatly welcome.
You are putting too much into the base class. Not all animals can do all the stuff that others can as well. Your animal class should only contain stuff that any animal can have/do. All the stuff that is specific for a concrete animal (i.e. a dog or a frog) should be placed into the corresponding class. For example, not every animal can bark(), definitely, so this function should not be in the base class.
How would you suggest counting the frogs and figuring whether they get eaten, played with, or let go?
Well since its the dog who can see the frogs, it would make sense to put a counter into the dog class.
Also I want to assign each animal subclass a number in which I can
then randomize in the main function so as to correlate with the
assignment but I am unsure as to how that would be done.
I didn't quite understand what do you mean here. Do you mean that you want to make identifiers for each class? If yes, why would you need to do it?
UPD:
Yes that's a right approach. The easiest way is to assign numbers from 1 to 6 for each animal, and then when you need to determine which one appears, generate a random number in the range of [1,6]. To assign numbers to the animals, you should add a field like int id; and assign different values to it in each class.
UDP 2:
This is where polymorphism comes into play. First of all, to initialize a const member for a class, you need to make it static. Here's a simple example:
class base
{
public:
static const int ID = -1;
};
class derived: public base
{
public:
static const int ID = 1;
};
Now every object of the base class will have an ID of -1, and every object of the derived class will have an ID of 1. However, if you try to use it from a base-class-pointer like this:
base * a = new derived();
int t = a->ID;
you will always be getting -1, since the base class pointer doesn't know what is it pointing it.
To get a correct ID you will need to make a virtual function:
virtual int getId(){ return ID; }
Now if you will do
base * a = new derived();
int t = a->getID();
you will always get the right ID from the "real" type a points at.
I suggest you put the random logic outside the tool... separation of concerns. Then you can have one program that just reads a series of animal names from standard input, performs the actions and records whatever it needs, then when it detects end-of-file prints a summary report. You can test it simply as in:
echo cat frog frog squirrel frog | buddy_simulator
If you want, you can then create a program to randomise some input.
The basic logic should be:
std::string animal_name;
while (std::cin >> animal_name)
{
// do something animal_specific
}
// do reporting
The animal specific behaviour could be created using a factory method accepting the animal_name parameter and returning an appropriate Animal* to a newly heap allocated animal object. You could then call p->suffer_buddy();, which would update a static member "times this animal's been seen" counter, print out what buddy likes to do (on this sighting). If it's the first time that animal's been seen, you could store the pointer into a vector in main(), so that when you want to do a summary report, you could call p->report() for each animal type you've encountered. Frog::report(), for example, might be something like:
void Frog::report()
{
std::cout << "of " << count_ << " frogs, " << eaten_ << " eaten, " << played_with_ << " played with, " << let_go_ << " let go\n";
}
It's a bit ugly to use so many static variables, but it's easier to make it work like this.
(Unfortunately, the behaviour's badly specified - how do you decide whether buddy's hungry? That's no specified at all, so you have to make some assumptions (and document them) or ask your teacher to specify this.)
This is all pretty stupid, but then so is modelling this problem using a polymorphic hierarchy, so there you go....