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....
Related
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!
I present my question in this simple form:
class animal {
public:
animal() {
_name="animal";
}
virtual void makenoise(){
cout<<_name<<endl;
}
string get_name(){
return _name;
}
protected:
string _name;
};
class cat : public animal {
public:
cat() {
this->_name="cat";
}
};
class dog : public animal {
public:
dog() {
this->_name = "dog";
}
};
I want to store all animal types together in a single container such as:
vector<animal*> container;
barnyard.push_back(new animal());
barnyard.push_back(new dog());
barnyard.push_back(new cat());
At some point in my code, I need to convert a dog object into a cat object. And all I need from this converting is to set up a fresh dog object and replace it at the same index number as a cat counterpart was located. As I understood, dynamic_cast wouldn't work in this case and based on C++ cast to derived class, it's mentioned that such a conversion is not a good practice. Since cat and dog in my model have distinct behavioral properties, I don't want to put their definitions into the animal model. On the other hand, storing them separately in different vectors would be difficult to handle. Any suggestions?
You say:
I need to convert a dog object into a cat object.
But then:
And all I need from this converting is to set up a fresh dog object and replace it at the same index number as a cat counterpart was located.
Do you need to convert it or replace it?? That's a completely different operation.
To convert you need to setup a function that will take a dog and return a cat:
auto convertDogToCat(Dog const& dog) -> Cat {
auto cat = Cat{};
// fill cat's member using dog's values...
return cat;
}
But to replace simply reassign with a new one:
// v--- a cat is currently there
barnyard[ii] = new Dog{};
// ^--- we replace the old pointer
// with one that points to a dog.
But that creates a memory leak, to remove the leak, simply use std::unique_ptr:
#include <memory> // for std::unique_ptr
// The base class need a virtual destructor
class animal {
public:
virtual ~animal() = default;
// other members...
};
std::vector<std::unique_ptr<animal>> barnyard;
barnyard.emplace_back(std::make_unique<animal>());
barnyard.emplace_back(std::make_unique<dog>());
barnyard.emplace_back(std::make_unique<cat>());
barnyard[ii] = std::make_unique<Dog>();
Here’s an alternative approach. Doesn’t use OOP or dynamic dispatch, but provides equal functionality to your sample. Also much faster, because no dynamic memory is required to allocate/free, animals are single bytes.
enum struct eAnimalKind : uint8_t
{
Generic = 0,
Cat = 1,
Dog = 2,
};
string get_name( eAnimalKind k )
{
static const std::array<string, 3> s_names =
{
"animal"s, "cat"s, "dog"s
};
return s_names[ (uint8_t)k ];
}
void makenoise( eAnimalKind k )
{
cout << get_name( k ) << endl;
}
If your classes keep more state than a type, use one class with that enum as a member.
If some animals use custom set of fields/properties it gets tricky but still possible, nested structures for specie-specific state, and std::variant of these structures inside class animal to get track on the specie and keep the data. In this case you no longer need enum eAnimalKind, std::variant already tracks the type it contains.
Classic C++ OOP requires dynamic memory. Derived classes generally have different sizeof, you can’t keep them in a single vector you can only keep pointers, and in runtime you’ll hit RAM latency on accessing every single element.
If your animals are large and complex i.e. megabytes of RAM and expensive methods, that’s fine. But if your animals are small, contain a couple of strings/numbers, and you have a lot of them, RAM latency will ruin the performance of OOP approach.
I have a situation where class A, B, and C, all are derived from X to make a composite pattern.
Now A, B, and C are very similar but they do have different internal attributes. My question is how do I access their attributes and modify them once they are added to composite without typecasting it?
In my real example, the part-whole relationship perfectly makes sense and all elements support the main operation which is why I need it. That said individual classes in the composite does have different attributes and requires special operations.
Is there a way to decouple these special properties and functions related to them away from composite class but attach to them?
To put things in perspective, let's say we have composite merchandise (base class of composite) which has a price. Now a store is a merchandise, in it, a department is a merchandise, in which an actual item say a potis merchandise, it can have a pot-set with combination pots which is also merchandise and so on.
class Merchandise
{
public:
virtual void add(Merchandise* item) = 0;
virtual Merchandise* getMerchandise() = 0;
virtual void show() = 0;
// assume we have the following key operations here but I am not implementing them to keep this eitemample short
//virtual setPrice(float price) = 0;
//virtual float getPrice() = 0;
};
class Store : public Merchandise
{
vector< Merchandise*> deparments;
std::string storeName = "";
public:
Store(std::string store_name) : storeName(store_name) {}
virtual void add(Merchandise* item)
{
deparments.push_back(item);
}
virtual Merchandise* getMerchandise()
{
if (deparments.size() > 0)
return deparments[0];
return 0;
}
virtual void show()
{
cout << "I am Store " << storeName << " and have following " << deparments.size() << " departments" << endl;
for (unsigned int i = 0; i < deparments.size(); i++)
{
deparments[i]->show();
}
}
};
class Department : public Merchandise
{
std::string depName;
vector<Merchandise*> items;
public:
Department(std::string dep_name) : depName(dep_name) {}
virtual void add(Merchandise* item)
{
items.push_back(item);
}
virtual Merchandise* getMerchandise()
{
if (items.size() > 0)
return items[0];
return 0;
}
virtual void show()
{
cout << "I am department " << depName << " and have following " << items.size() << " items" << endl;
for (unsigned int i = 0; i < items.size(); i++)
{
items[i]->show();
}
}
};
class Shirt : public Merchandise
{
std::string shirtName;
public:
Shirt(std::string shirt_name) : shirtName(shirt_name) {}
virtual void add(Merchandise* item) {}
virtual Merchandise* getMerchandise() { return 0; }
virtual void show()
{
cout << "I am shirt " << shirtName << endl;
};
};
class Pot : public Merchandise
{
std::string potName;
public:
Pot(std::string pot_name) : potName(pot_name) {}
virtual void add(Merchandise* item) { }
virtual Merchandise* getMerchandise() { return 0; }
virtual void show()
{
cout << "I am pot " << potName << endl;
};
int num = 0;
};
class CookSet : public Merchandise
{
std::string cooksetName;
vector<Merchandise*> pots;
public:
CookSet(std::string cookset_name) : cooksetName(cookset_name) {}
vector<Merchandise*> listOfPots;
virtual void add(Merchandise* item) { pots.push_back(item); }
virtual Merchandise* getMerchandise() { return 0; }
virtual void show()
{
cout << "I am cookset " << cooksetName << " and have following " << pots.size() << " items" << endl;
for (unsigned int i = 0; i < pots.size(); i++)
{
pots[i]->show();
}
};
int num = 0;
};
int main()
{
// create a store
Store * store = new Store( "BigMart");
// create home department and its items
Department * mens = new Department( "Mens");
mens->add(new Shirt("Columbia") );
mens->add(new Shirt("Wrangler") );
// likewise a new composite can be dress class which is made of a shirt and pants.
Department * kitchen = new Department("Kitchen");
// create kitchen department and its items
kitchen->add(new Pot("Avalon"));
CookSet * cookset = new CookSet("Faberware");
cookset->add(new Pot("Small Pot"));
cookset->add(new Pot("Big pot"));
kitchen->add(cookset);
store->add( mens );
store->add(kitchen);
store->show();
// so far so good but the real fun begins after this.
// Firt question is, how do we even access the deep down composite objects in the tree?
// this wil not really make sense!
Merchandise* item = store->getMerchandise()->getMerchandise();
// Which leads me to want to add specific method to CStore object like the following to retrieve each department
// but then does this break composite pattern? If not, how can I accomodate these methods only to CStore class?
//store->getMensDept();
//store->getsKitchenDept();
// Likewise a shirt class will store different attributes of a shirt like collar size, arm length etc, color.
// how to retrieve that?
// Other operations is, say if item is cookset, set it on 20% sale.
// Another if its a shirt and color is orange, set it on 25% sale (a shirt has a color property but pot doesn't).
// how to even dispaly particular attributes of that item in a structure?
// item->getAttributes();
return 0;
}
The problem is with this line once I have filled up the composite.
Merchandise* item = store->getMerchandise()->getMerchandise();
First, from my code structure, I know this should be a certain type but as a best practice, we are not supposed to typecast this!? But I do want to change its properties which are unique to it so how do I achieve that?
Assume this store sells shirts as well and I want to change its properties (or even just to display them!), it is very different from a pot.
What would be the best approach here? I think if we can somehow decouple the unique properties of each composite into different classes, this way composite will stay leaner too but not sure how to achieve that.
I assume, in real life, there is no perfect composite and the constituent classes will have some differences. How do we handle that?
Update
Please note I have used the merchandise example to explain the problem. In my real example, A, B, C are all derived from X. A contains multiple B which contains multiple C items. When an operation is performed on A, it needs to be performed on its constituents and that's why I am using composite. But then, each composite does have different attributes. Is composite not a good fit for this?
I think you are looking for the visitor design pattern, it keeps clean interfaces and makes code much more flexible.
class Shirt;
class Pot;
class visitor{
public:
//To do for each component types:
virtual void visit(Shirt&) =0;
virtual void visit(Pot&) =0;
};
class Merchandise
{
public:
//...
//Provides a default implementation for the acceptor that
//that do nothing.
virtual void accept(visitor& x){}
// assume we have the following key operations here but I am not implementing them to keep this eitemample short
//virtual setPrice(float price) = 0;
//virtual float getPrice() = 0;
// => implementable with a visitor
};
class Store : public Merchandise
{
//...
void accept(visitor& v) override
{
for (unsigned int i = 0; i < deparments.size(); i++)
{
//forward the visitor to each component of the store.
//do the same for departments
deparments[i]->accept(v);
}
}
};
class Shirt : public Merchandise
{
//...
void accept(visitor& v) override{
//now *this as the type Shirt&, pass this to the visitor.
v.visit(*this);
}
};
class Pot : public Merchandise
{
//...
void accept(visitor& v) override{
v.visit(*this);
}
};
class SpecialPromotion
:public visitor{
public:
void visit(Shirt& s) override {
//25% discount on orange shirts, 15% otherwise;
if (s.color="orange")
s.price*=0.75;
else
s.price*=0.85
}
void visit(Pot& p) override{
//one pot offered for each pot pack
++p.num;
}
};
//example of usage:
void apply_special_promotion(Store& s){
SpecialPromotion x;
s.accept(x);
}
class EstimateStockMass
:public visitor{
public:
double mass=0;
void visit(Shirt& s) override {
if (s.size="XL") mass+=0.5;
else mass+=0.1;
}
void visit(Pot& p) override{
mass += p.num * 1.2;
}
};
//example of usage:
double get_stock_mass(Store& s){
EstimateStockMass x;
s.accept(x);
return x.mass;
}
It seems like what you want to do is gathering RTTI (Run-time type information), so dynamic_cast is the solution. Also, if you are using C++17, I will recommend you use std::variant (or boost::variant if you are using lower version of C++ but are using boost.) If you do not want to use them, then maybe you can make your add a template function and returns a reference to the underlying type.
By the way
in your main there are a bunch of dynamic allocations that never get deallocated. Use smart pointers if you have C++ with version at least C++11.
your base classes do not have virtual destructors, this will cause huge problems when destroying your store
Don't use using namespace std
If you have C++11, use override keyword when you want to override a virtual function
You should mark show() const.
Merchandise: a commodity offered for sale
Now a store is a merchandise,
This is true only if you are selling the store. Otherwise it is better described as a container of merchandise, not a composite.
Even if you are in the business of selling stores, it might (depending on the context of the program) be prudent to treat it as a different kind of merchandise (different base class) since the selling environment is rather different.
in it, a department is a merchandise,
Departments within a store are rarely sold to other stores, so I highly doubt this claim. Again, you have something that contains merchandise, not something composed of merchandise.
in which an actual item say a pot is merchandise, it can have a pot-set with combination pots which is also merchandise and so on.
Yes, this much is good. Pots are offered for sale. A pot-set combination sounds like a good example of composite merchandise, as the set is offered for sale, and its components might be packaged and offered for sale separately, perhaps even on the same shelf.
Speaking of the shelf, that would be another example of a container of merchandise.
It looks like you might be after containers rather than composites. A store could have a vector of departments (or perhaps a set if you want to find them by name). The department in turn could have a container of merchandise within that department. Or perhaps the department would contain aisles, which then contain shelves, which then contain merchandise.
If you need the inventory of the entire store, there are a few options. One would be to have the store iterate over its departments, which then iterate over their inventories. Ideally, you would implement this within the store class so that code outside the class does not need to know about this structure. Another option would be for the store to maintain its own container of merchandise. This would mean that a single item of merchandise would logically be in multiple containers (e.g. a store's and a department's). This suggests using containers of shared_ptr, so that each item of merchandise is still represented by a single data object.
Regardless of the implementation chosen, the relationship between "store" and "merchandise" is better described as "has" rather than "is".
Concerning Your Design Choices
Let's compare the GoF book description of the intent of the Composite pattern with your requirements:
Compose objects into tree structures that represent whole-part hierarchies.
In your example a shirt is not part of a shop, and a shop is not really an item of merchandise.
You say this does make sense in your actual code, but I can only comment on the code you actually showed.
Composite lets clients treat individual objects and compositions of objects uniformly.
In your comment you say you don't really want to treat each type of object uniformly.
So, it's at least not obvious that Composite is a good fit, because the description doesn't match your use case (at best, it half-fits your described use case but not your sample code).
For comparison, the motivating example from that book is a drawing app, where treating the main canvas as a Drawable object containing other Drawable sub-objects (of different types like lines, polygons and text) is useful for rendering. In that case each object is a drawable part of the drawable whole, and it focuses on the case when you do want to treat them uniformly (ie, issuing a single draw call to the top-level canvas).
A match has an innings (has score/result), both side which are playing has their inning (has scores), then each player who is playing has his innings (score with more details). When match progresses, an event is added to the match which than is added to current innings and than current player innings. So I build up score this way but at the end I want to display it and each innings type is rather different and setting up current state requires different operations.
OK, an innings is part of a match, but do you have any more levels? Does an innings consist of balls or other events, or is it just ... an innings number, a player and a score?
If you can easily model a game as a list of innings, and link each innings to a player for per-player reports, that seems a lot simpler.
Even if you have another level, if you only want to deal with objects heterogeneously (according to their different types, instead of homogeneously as if they're all the same), you can just write that structure explicitly.
Concerning Your Composite Implementation
The getMerchandise interface is poor. Why does it return only the first of potentially many objects? Why do you need to get them anyway?
You mention two use cases:
changing an object's properties
Presumably you know which object you want to alter, right? Say you want to change the price of the object loosely identified as Mens>Shirts>Wrangler. Either
ask the store to forward a Visitor to that object by name (so the store finds the department called "Mens" and asks that to forward the Visitor to a child matching Shirts>Wrangler).
just find the Shirt("Wrangler") object directly in some other index (eg. by stock number) and deal with it directly. You don't have to do everything via the Composite pattern even if you do use it.
displaying an object
But the whole point of the Composite pattern is that every object should implement a virtual display (or whatever) method. You use this when you want to let every type know how to display itself.
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 need some help figuring this out if it is possible. I am still very new to this so please forgive me. I have an array of an object that I want a method to manipulate for me. I'm not sure how to best put this in words so I will use an example.
#include <iostream>
using namespace std;
class fruit
{
private:
int amount;
public:
void eat();
};
void fruit::eat()
{
//manipulate the amount for apples at both indexes here
}
int main()
{
fruit apples[2];
fruit pie;
pie.eat();
return 0;
}
I want to change the amount at both indexes in the apples array using the eat() function. How would I go about doing this. I'm sorry if this seems stupid.
Well actually your question as well as many of the answers don't seem correct, because it doesn't make sense fruit eating fruit. What does it mean "fruit eating fruit"? Could you please explain?
A possible and reasonable class design should do something like this:
class person
{
public:
void eat(edible *item) {}
void drink(drinkable *item) {}
void sleep(double duration) {}
//...
};
class edible
{
public:
virtual ~edible() {}
virtual double get_calories() = 0; //pure virtual function
//...
}
class fruit : public edible
{
public:
virtual double get_sweetness() = 0; //pure virtual function
//...
}
class apple : public fruit
{
public:
//define pure virtual functions
}
class banana : public fruit
{
public:
//define pure virtual functions
}
std::vector<edible*> items;
items.push_back(new apple());
items.push_back(new apple());
items.push_back(new banana());
items.push_back(new banana());
person nawaz;
for(int i = 0 ; i < items.size() ; i++ )
nawaz.eat(items[i]);
nawaz.sleep(8 * 60 * 60); //8 hours!
I'm afraid that there are quite a few conceptual errors here.
To address your immediate question: your fruit class can't understand the "basket" it is in, so it's not reasonable to ask it to work on the basket.
When you say
fruit apples[2];
you are making two apple objects, each of which has an eat() method (I'll come back to that in a moment, because I'm not sure that makes sense) and then put them into an array. The array itself (I refered to it as a basket before) holds apples but does not have any eat() method. The apples do not have any knowledge that they are in the array. So in order to eat the apples you need some code to traverse the array (forgive this syntax, it's years since I wrote c++)
for ( int i = 0; i < 2; i ++ ){
apples[i].eat();
}
Now the question is where should that code go? And this is fundamental to the idea of OO programming, you think about what objects could reasonably "understand" this kind of operation, have responsibilities for looking after fruit. And hence you might have a Basket class, or some such.
Now onto the next object
fruit pie;
pie.eat();
Some problems here, first of all a pie is surely not a fruit. Consider all the things a fruit can do, and all the things a pie can do, they are very different - OK, you can slice them both, and eat them both, but they are no more similar than any other food. When you create classes you look for key similarities: Apples, Oranges, yep they have useful similarities perhaps, so Fruit as a class makes sense.
Second problem, I think you're expecting pie.eat() to have some effect on the array of apples. But these are completely distinct object. Two objects of the same class do not usually know ablout each other (there's some advanced techniques for making that possible, but don't even think about this now).
Now onto the final and I think most crucial point: the eat() method. In my world apples don't eat things, nor do they eat themselves. When doing OO, to a large extent you are modelling the real world. When you get something like this, a method that doesn't really correspond to the objects in question it probably implies that there is another class of objects we haven't identified yet.
It's not clear what kind of actions you are modelling. If you are tracking your inventory of fruit then you might have a Basket class. With methods such as
addFruit( arrayOfFruit);
takeFruit( what kind of fruit I want);
howManyFruit(kind of fruit);
If you are modelling calorie consumption you might have methods on Fruit
calories = takeOneBite();
biteLeft = howManyBitesLeft();
So we need to understand what you really want to do with the fruit before we can help further.
First of all, no need to ask for forgiveness, websites like stackoverflow exist so questions get answered. If anyone ever has a "smart-ass" attitude towards you, it's their problem, not yours.
Now, to your question: In your eat() method you have a comment stating that you want to manipulate the amount for apples. But that method belongs to the whole fruit class so what you really want is to manipulate the amount for any given fruit, right? Also, it's not very clear what exactly you want to manipulate so if you could provide a better explanation I guess you will get a lot more answers.
I will be waiting! :)
You need to pass the apples array to eat function. Something like this:
void fruit::eat(fruit* apples, unsigned int count)
{
for(unsigned int apple = 0; apple < count; ++apple)
{
apples[apple].amount = 0;
}
}
and in main()
{
pie.eat(apples,2)
}
You can't, not from within the class method (function). A method always works for one instance, like your fruit pie. The arrays of apples are two instances, so you just call eat() on each of them:
fruit apples[2];
apples[0].eat();
apples[1].eat();
Since the pie object needs to modify apples, one of way of implementing is to overload fruit::eat() to take an argument of type fruit*.
#include <iostream>
using namespace std;
class fruit
{
private:
int amount;
public:
void eat(fruit *obj);
void eat(){};
};
void fruit::eat(fruit *obj)
{
obj[0].amount = 10; // Modify here to what ever value you need
obj[1].amount = 20;
}
int main()
{
fruit apples[2];
fruit pie;
pie.eat(apples);
return 0;
}
Results: ideone . Also note that this is doing what you had asked in question but the design is bad though.