Help with Object Oriented Programming with C++ - c++

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.

Related

c++ Using subclasses

I have this variable; Furniture **furnitures;
Which is an abstract baseclass to 2 subclasses, Bookcase and Couch. I add these randomly;
furnitures[n++] = new Bookcase ();
furnitures[n++] = new Couch();
.
.
For the sake of explaination. Lets set some minor variables.
Furniture private: name, prize
Bookcase private: size
Couch private: seats
How would I go about if I wanted to print out information such as; name and seats?
There are various of problems in this issue. 1, distinguish which subclass is which when I use Furniture[i]. 2, I dont want to blend too much unneccessary functions between the two subclasses that arent needed.
class Furniture
{
virtual void output() = 0;
};
class Couch : public Furniture
{
void output() override;
};
class Bookshelf : public Furniture
{
void output() override;
};
You could define the function in Furniture to save from duplicate code in subclasses like this:
void Furniture::output()
{
// We assume here the output is to cout, but you could also pass the necessary
// stream in as argument to output() for example.
cout << name << price;
}
void Couch::output()
{
Furniture::output();
cout << seats;
}
void Bookshelf::output()
{
Furniture::output();
cout << size;
}
You should never use arrays polymorhphically. Read the first item (I think it's the first) in Scott Meyers' More Effective C++ book to find out why!
In fact, you should almost never use raw arrays in C++ anyway. A correct solution is to use a std::vector<Furniture*>.
How would I go about if I wanted to print out information such as;
name and seats?
There are various of problems in this issue. 1, distinguish which
subclass is which when I use Furniture[i]. 2, I dont want to blend too
much unneccessary functions between the two subclasses that arent
needed..
You are facing this problem because you are abusing object-oriented programming. It's simple: object-oriented programming makes sense when different types implement an abstract common operation and the concrete type is chosen at run-time. In your case, there is no common operation. Printing (or receiving) the number seats is for one type, printing (or receiving) a size is for the other type.
That's not to say that it's bad or wrong, but it's simply not object-oriented.
Now C++ would not be C++ if it didn't offer you a dangerous tool to get out of every dead end you've coded yourself into. In this case, you can use Run-Time Type Identifcation (RTTI) to find out the concrete type of an object. Google for typeid and dynamic_cast and you'll quickly find the solution. But remember, using RTTI for this problem is a workaround. Review your class design, and change it if necessary.

What is the right way to use polymorphism and inheritance in C++ to handle a basket of fruit?

Say I'm coding a robot that processes a basket of fruit. Oranges need to be juiced, apples need to be sliced, and bananas need to be peeled. Fortunately, our robot has the exact tools needed for juicing, slicing, and peeling.
Robot::processFruit(List<Fruit*> basket)
{
foreach(Fruit *fruit, basket)
{
if( ? ) { juiceIt(fruit); }
else if( ? ) { sliceIt(fruit); }
else if( ? ) { peelIt(fruit); }
}
}
This is a generic example of a problem that I am occasionally confronted with. I have a gut feeling that there is something wrong in my design such that I am even led to a processFruit() function, as I'm using an object oriented language, but it doesn't appear to have a clean solution to this problem.
I could create an enum FruitType { Orange, Apple, Banana} then require each fruit to implement virtual FruitType fruitType(), but then it seems I'm just re-implementing a type system.
Or I could have functions virtual bool isOrange(); virtual bool isApple(); ... but as we can see that would get out of hand very quickly.
I could also use C++'s typeid, but this wikibook says
RTTI should only be used sparingly in C++ programs.
So I am reluctant to take that approach.
It seems that I must be missing something fundamental and crucial in the design of an object oriented program. C++ is all about inheritance and polymorphism, so is there a better way to approach this problem?
Update: I like the idea of having a generic process() function that all Fruit are required to implement. But what if I now want to add a Lemon and want to juice that? I don't want to duplicate the juicing code, so should I create a class Juicable : public Fruit and have Oranges and Lemons both be Juicable?
See Tell, don't ask:
Procedural code gets information then makes decisions. Object-oriented code tells objects to do things.
— Alec Sharp
You want to define a base Fruit class, which has a virtual process method. Apples, oranges and bananas would each implement their own version of process which does the correct thing for that type of fruit. All your robot needs to do is pull the next Fruit* out of the basket, and call process on it:
Robot::processFruit(List<Fruit*> basket)
{
foreach(Fruit *fruit, basket)
fruit->process();
}
The kind of if/else/else handling you're doing in your code example is exactly the kind of thing that polymorphism is meant to avoid, and it's definitely not doing this the "OOP" way.
The way I would handle this situation is to create a superclass called Fruit with a pure virtual method called process(). Orange, Apple and Banana will all superclass fruit, and each of them will provide an implementation of process() which takes the appropriate action for that particular type (i.e., subclass) of fruit.
So your loop would look more like:
Robot::processFruit(List<Fruit *> basket)
{
foreach(Fruit *fruit : basket)
{
fruit->process();
}
}
Otherwise, Robot's function would basically need a way to determine the type of fruit it's dealing with. Typically when I need to do this, I simply try to dynamic_cast<>() the Fruit pointer to whatever other type it might be. For instance, suppose I have a Fruit * to an object that is a Banana. I would take advantage of the following:
Fruit *f = new Banana();
Orange *o = dynamic_cast<Orange *>(f); // o is NULL, since f is NOT an Orange.
Banana *b = dynamic_cast<Banana *>(f); // b points to the same object as f now.
However, the first solution is, in my opinion, far cleaner and more respectful of object oriented programming. The second solution is sometimes useful, but should be used sparingly.
Update: If you really want the Robot to do the processing code, then I would suggest, instead of having the Robot call process(), have your robot class implement the processing methods, and then have the fruit itself take advantage of the robot - e.g.:
Robot::juiceIt(Orange *o)
{
// ...
}
Robot::sliceIt(Apple *a)
{
// ...
}
Robot::peelIt(Banana *b)
{
// ...
}
Orange::process(Robot *r)
{
r->juiceIt(this);
}
Apple::process(Robot *r)
{
r->sliceIt(this);
}
Banana::process(Robot *r)
{
r->peelIt(this);
}
I think #meagar has the better solution but I want to put this out there.
Robot::processFruit(List<Fruit*> basket)
{
foreach(Fruit *fruit, basket)
fruit->process(*this);
}
Orange::process(Robot & robot) {
robot.JuiceIt(*this);
}
This solution say a fruit needs a robot to process it.
If I really, really needed to solve this problem and I couldn't engineer my way around it... I'd write a type-aware double dispatch processor, and use it as a single-dispatch on the argument type only.
First, write a functions class that is a type erased function overload set. (This isn't trivial!)
typedef functions< void(Apple*), void(Orange*), void(Banana*) > processors;
Second, maintain a set of FruitTypes in a compile time list:
type_list< Apple, Orange, Banana > CanonincalFruitTypes;
typedef functions< void(Apple*), void(Orange*), void(Banana*) > FruitProcessor;
this has to be maintained somewhere. The relationship between these two lists can be automatic with a bit of work (so FruitProcessors is produced from CanonicalFruitTypes)
Next, write a reflection style dispatch:
class Fruit {
public:
virtual void typed_dispatch( FruitProcessor ) = 0;
virtual void typed_dispatch( FruitProcessor ) const = 0;
};
template<typename Derived>
class FruitImpl: public Fruit {
static_assert( std::is_base< Derived, FruitImpl<Derived> >::value, "bad CRTP" );
static_assert( /* Derived is in the Fruit type list */, "add fruit type to fruit list" );
Derived* self() { return static_cast<Derived*>(this); }
Derived const* self() const { return static_cast<Derived*>(this); }
virtual void typed_dispatch( FruitProcessor f ) final overrode {
f(self());
}
virtual void typed_dispatch( FruitProcessor f ) const final overrode {
f(self());
}
};
Use tricks to make deriving from Fruit not through a FruitImpl illegal (friend and private based stuff).
then, the Robot can go to town:
void Robot::process( Fruit* fruit ) {
fruit->typed_dispatch( MyHelperFunctor(this) );
}
where MyHelperFunctor returns a functor with overrides for the various types of Fruit the Robot can handle, and functions<...> has to be smart enough to test that each signature it supports can be handled by the passed in functor (this is the non-trivial part) and do proper dispatch to them.
If someone derived from Fruit, they do it via FruitImpl, which enforces it being in the fruit list. When the fruit list changes, the typed_dispatch signature changes, which requires that all users of it implement an override that can accept every fruit type in the list.
This allows you to decouple the virtual behavior of Fruit when processed by a Robot from the Fruit implementation itself, while enforcing compile-time checks that all types are handled. If their is a hierarchy of Fruit, the Robot's helper functor can make compile-time decisions to dispatch the call based on that heirarchy (which is translated into a run-time decision in functions). The overhead is an extra virtual function call (for the type-erased functions), and the construction of the type-erased functions object.
This is almost a text book case for the Visitor pattern. In the sample below I'm not using the standard visitor pattern class or function names, rather I'm using names that are relevant to the domain in this case - i.e. FruitProcessor and Process, rather than Visitor and Apply. I'm not going to comment much further as I think the code is pretty self explanatory other than to mention that this design requires the FruitProcessor to be manually updated when adding more types of fruit. There are various ways to handle that including registering fruit processing handlers or even using an abstract fruit processing factory (see abstract factory for more details). I would like to mention that there is another way that definitely requires a look and that was presented at boostcon by Sean Parent: see it on Youtube: Value Semantics and concept based polymorphism
class Apple;
class Orange;
class FruitProcessor
{
public:
virtual void Process(Apple& apple) = 0;
virtual void Process(Orange& orange) = 0;
};
class Fruit
{
public:
virtual void Process(FruitProcessor& proc) = 0;
};
class Apple : public Fruit
{
public:
virtual void Process(FruitProcessor& proc) override
{
proc.Process(*this);
}
};
class Orange : public Fruit
{
public:
virtual void Process(FruitProcessor& proc) override
{
proc.Process(*this);
}
};
class RobotFruitProcessor : public FruitProcessor
{
public:
virtual void Process(Apple& apple) override
{
std::cout << "Peel Apple\n";
}
virtual void Process(Orange& orange) override
{
std::cout << "Juice Orange\n";
}
};
int main()
{
std::vector<Fruit*> fruit_basket;
fruit_basket.push_back(new Apple());
fruit_basket.push_back(new Orange());
RobotFruitProcessor rfp;
for(auto f : fruit_basket)
{
f->Process(rfp);
}
return 0;
}

C++ counting animals and random interaction with base class

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....

multiple classes, same public interface

ok, after last night I've decided to rephrase my question for easier reading.
I have 2 classes, Army and Battle groups. heres the classes below, albeit with some parts missing:
class Battlegroups
{
private: battlegroup battlegroupobject[100];
public:
void AddBattleGroup(); //add a battlegroup object to the array
void removebattlegroup(); //remove a battle group objects from the array
};
class Army
{
private: battlegroups battlegroupsobject;
public:
void formbattlegroup()
{
battlegroupsobject.AddBattleGroup();
}
void disbandbattlegroup()
{
battlegroupsobject.removebattlegroup();
}
};
See, the problem is the formbattlegroup() and the disbandbattlegroup(), which seems like its adding a pointless interface.
if there is a way for me to access the Addbattlegroup and removebattlegroup() methods without doing the above, please tell me.
or, tell me if this is the way you do it, but to me, it seems like adding code, for the sake of code.
If Battlegroups is used only for containing objects, you may use battlegroup battlegroupobject[100] right in the Army instead. Or use std::vector<battlegroup> instead of battlegroups. If not (and anyway), your decision seems quite correct, because there are different responsibilities of these objects.
not very sure about your design, but here is my guess: you want to have Army, Navy etc. Then you may want to inherit Army, Navy from Battlegroups, such that you don't need to write AddBattleGroup and RemoveBattleGroup for every classes for Army, Navy etc . Like the following:
class Battlegroups
{
// side-note: you may want to replaced below by std::vector<battlegroup>
private: battlegroup battlegroupobject[100];
public:
void AddBattleGroup();
void RemoveBattleGroup();
};
class Army
: public Battlegroups
{
// other specific implementations
};
class Navy
: public Battlegroups
{
// other specific implementations
};
// usage
Army army1;
army1.AddBattleGroup();
Navy navy1;
navy1.AddBattleGroup();
If this is not what you want, you may want to consider Dmitry's answer.

Apples, oranges, and pointers to the most derived c++ class

Suppose I have a bunch of fruit:
class Fruit { ... };
class Apple : public Fruit { ... };
class Orange: public Fruit { ... };
And some polymorphic functions that operate on said fruit:
void Eat(Fruit* f, Pesticide* p) { ... }
void Eat(Apple* f, Pesticide* p) { ingest(f,p); }
void Eat(Orange* f, Pesticide* p) { peel(f,p); ingest(f,p); }
OK, wait. Stop right there. Note at this point that any sane person would make Eat() a virtual member function of the Fruit classes. But that's not an option, because I am not a sane person. Also, I don't want that Pesticide* in the header file for my fruit class.
Sadly, what I want to be able to do next is exactly what member functions and dynamic binding allow:
typedef list<Fruit*> Fruits;
Fruits fs;
...
for(Fruits::iterator i=fs.begin(), e=fs.end(); i!=e; ++i)
Eat(*i);
And obviously, the problem here is that the pointer we pass to Eat() will be a Fruit*, not an Apple* or an Orange*, therefore nothing will get eaten and we will all be very hungry.
So what I really want to be able to do instead of this:
Eat(*i);
is this:
Eat(MAGIC_CAST_TO_MOST_DERIVED_CLASS(*i));
But to my limited knowledge, such magic does not exist, except possibly in the form of a big nasty if-statement full of calls to dynamic_cast.
So is there some run-time magic of which I am not aware? Or should I implement and maintain a big nasty if-statement full of dynamic_casts? Or should I suck it up, quit thinking about how I would implement this in Ruby, and allow a little Pesticide to make its way into my fruit header?
Update: Instead of the contrived bit with the bare Eat functions and Pesticide, suppose instead that I just don't want to put Eat in the fruit because it makes no sense. A fruit that knows how to eat itself? Pshaw. Instead I need an Eater class with an Eat function, with different code for eating each kind of fruit, and some default code in case it's a fruit that the eater doesn't recognize:
class Eater
{
public:
void Eat(Apple* f) { wash(); nom(); }
void Eat(Orange* f) { peel(); nom(); }
void Eat(Fruit* f) { nibble(); }
};
...
Eater me;
for(Fruits::iterator i=fs.begin(), e=fs.end(); i!=e; ++i)
me.Eat(*i); //me tarzan! me eat!
But again, this doesn't work, and the straightforward solution in C++ seems to be a bunch of calls to dynamic_cast.
However, as one of the answers suggests, there may be another clever solution. What if Fruits exposed the qualities that mattered to eaters, with functions like MustPeel() and MustWash()? Then you could get by with a single Eat() function ...
Update: Daniel Newby points out that using Visitor also solves the problem as presented ... but this requires a bit of a semantic headstand (Fruit::use or Fruit::beEaten?).
While I'd like to accept several answers, I think psmears's answer is actually the best one for future readers. Thanks, everyone.
You need to redesign. Namely, do everything you seem to be avoiding (for what reason, who knows.)
Polymorphic behavior requires polymorphic functions. This means a virtual function. (Or your ladder of dynamic_cast's, which completely defeats the purpose...)
// fruit.h
class Pesticide; // you don't need a complete type
struct Fruit
{
virtual void Eat(Pesticide*) = 0;
};
// apple.h
class Apple : public Fruit
{
void Eat(Pesticide* p) { ... }
};
// orange.h
class Orange : public Fruit
{
void Eat(Pesticide* p) { ... }
};
If you still want a free function*:
void Eat(Fruit* f, Pesticide* p) { f->Eat(p); }
*Note that your post is already indicative of bad design; namely the first Eat function:
void Eat(Fruit* f, Pesticide* p) { }
When does doing nothing to a fruit equate to eating the fruit? A pure virtual function is a much better interface choice.
When a question like this comes up, it's good to look at exactly why you want to make particular decisions - for instance, why do you not want the Fruit classes to know about Pesticide?
I'm sure there is a good reason for this - but expressing that reason will help clarify in your mind exactly what your aims are - and this often sheds a new light on a possible angle for structuring the program.
For instance, you might end up adding new virtual methods "IsEdible" and "PrepareForEating". Then you can implement these for each fruit, and implement one generic Eat method that works for all fruits - and ingests the pesky pesticide too - all without the Fruit classes knowing anything about it.
Of course, depending on your precise aims, that may be totally inappropriate - which is why you'll have to clarify the example in your own head :-)
Just use the I Am Standing Right Here! Pattern. It's like the Visitor Pattern but without a container.
// fruit.h
class Fruit;
class Apple;
class Orange;
class Fruit_user {
public:
Fruit_user();
virtual ~Fruit_user();
virtual use(Apple *f) = 0;
virtual use(Orange *f) = 0;
};
class Fruit {
public:
// Somebody with strong template fu could probably do
// it all here.
virtual void use(Fruit_user *fu) = 0;
};
class Apple : public Fruit {
public:
virtual void use(Fruit_user *fu) {
fu->use(this);
}
};
class Orange: public Fruit {
public:
virtual void use(Fruit_user *fu) {
fu->use(this);
}
};
// dow-chemical.h
class Pesticide_fruit_user : public Fruit_user {
public:
Pesticide_fruit_user(Pesticide *p) {
p_ = p;
}
virtual void use(Apple *f) { ingest(f, p_); }
virtual void use(Orange *f) { peel(f, p_); ingest(f, p_); }
private:
Pesticide *p_;
};
There's nothing wrong with having arbitrary class pointers in headers. They form the basis of many idioms, like PIMPL and opaque pointers. Also, if you aren't a sane person, how are you supposed to understand my answer?
Seriously, derived functions and polymorphism exist to solve this problem. If you refuse to use the language provided tools, why bother using it at all? Any solution you can come up with can be translated into a virtual function call in any case, just you would have coded it manually instead of having the compiler do it.
What you're asking for isn't possible. The function overloading resolution needs to know at compile time which class the parameter is so it can call the correct Eat function. The only exception is for virtual member functions, which you've already ruled out.