Archived

This topic is now archived and is closed to further replies.

Finding which subclass

This topic is 5042 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I currently have a virtual superclass with 2 subclasses. I''m trying to resolve the question of "How do I know which subclass I''m working with". I''m trying to do something like the following, but it isn''t working because I''m not properly instantiating the virtual function. class animal { virtual fight(animal a); }; class dog : public animal { fight(dog d); fight(cat c); }; class cat : public animal { fight(dog d); fight(cat c); }; You can see that what I really want is subclass-specific funtions that I can always call from the animal class. That way if I have an array of animals I can just call fight without worrying what subclass all the array members are. My other option is to have one fight function that takes an animal, and somehow ''checks'' for type with a big case statement. EW. I''d like to avoid that if possible. But if its the only way... Any thoughts?

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Did I understand correctlz, that you want just one fight method for each class (which have the same parrent)?

If that''s right, why don''t you do it simply like this:

class animal
{
virtual fight(animal a);
};

class dog : public animal
{
fight(animal a);
};

class cat : public animal
{
fight(animal a);
};



Maybe I''ve misunderstood your problem... ;-)

Share this post


Link to post
Share on other sites
That probably is what I want. BUT,

How do I tell within each fight function what type I am dealing with? In other words, if a cat fights a dog differently than a cat fights a cat, I need to know the type of the animal I am fighting. Is that possible?


As a follow on, is it ever possible to have an array of animals that are all cats and dogs, or do I need to use pointers? I've heard that my animals will all get 'sliced' if I do something like

animal a[10];

dog d;
a[0] = d;

cat c;
a[1] = c;

And for my first question, I want to do this: (and have them fight differently depending on what they are fighting)

a[0].fight(a[1]);


[edited by - aargyle on February 22, 2004 6:29:29 PM]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
You could add a string or something to the animal class as an identifier... like:

class animal {
std::string type;
virtual fight(animal a);
};

Where type could be "dog" or "cat" then you would just use the big disgusting case statement in the function.

Share this post


Link to post
Share on other sites
quote:
How do I tell within each fight function what type I am dealing with? In other words, if a cat fights a dog differently than a cat fights a cat, I need to know the type of the animal I am fighting. Is that possible?
You can use C++'s function overloading. If you just make sure they know about each other in the example in your original post, your example should work fine.
quote:
As a follow on, is it ever possible to have an array of animals that are all cats and dogs, or do I need to use pointers?
You need to use an array of pointers (also try the STL's std::vector), and new/delete if you want:
Animal* AnimalArray[2];
AnimalArray[0] = new Cat;
AnimalArray[1] = new Dog;
delete AnimalArray[0];
delete AnimalArray[1];
However, this breaks with the previous solution:
AnimalArray[0]->Fight( AnimalArray[1] ); // calls Fight( Animal );

// solve with casting
AnimalArray[1]->Fight( static_cast<Dog>( AnimalArray[1] ) );


edit: Damn the forum parsing!

[edited by - psykr on February 22, 2004 7:00:43 PM]

Share this post


Link to post
Share on other sites
a) dog::fight(dog) does not override animal::fight(animal), like dog::fight(animal) would. One way to fix your problem is therefore to have animal::fight(dog) and animal::fight(cat) that are overriden in the derived classes, but overriding overloaded virtual functions is also tricky.

b) Remember to pass your parameters by reference, or you''ll have slicing problems. animal::fight(animal&).

c) Search the net for ''Double Dispatch'', Multiple Dispatch'', ''Multimethods''. See for example the WikiPedia or the Portland Pattern Repository.

d) Familiarize yourself with the Visitor, and RTTI Visitor patterns.

e) Read Alexandrescu''s "Modern C++ Design" book, chapter 11 "Multimethods", and Meyer''s "More Effective C++", Item 31: "Making functions virtual with respect to more than one object".

As a follow on, is it ever possible to have an array of animals that are all cats and dogs, or do I need to use pointers?

You need to use animal pointers.


“Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.”
— Brian W. Kernighan (C programming language co-inventor)

Share this post


Link to post
Share on other sites
What you want is Double Dispatch. google for it. One solution is this:


#include <iostream>

struct cat;
struct dog;

struct animal {
virtual void fight(animal& a) = 0;
virtual void fight(dog& a) = 0;
virtual void fight(cat& a) = 0;
};

struct dog : animal {
virtual void fight(animal& a)
{
a.fight(*this);
}
virtual void fight(dog& a)
{
std::cout << "dog vs. dog\n";
}
virtual void fight(cat& a)
{
std::cout << "cat vs. dog\n";
}
};

struct cat : animal {
virtual void fight(animal& a)
{
a.fight(*this);
}
virtual void fight(dog& a)
{
std::cout << "dog vs. cat\n";
}
virtual void fight(cat& a)
{
std::cout << "cat vs. cat\n";
}
};

int main()
{
dog d;
cat c;
animal& dr = d;
animal& cr = c;
dr.fight(dr);
dr.fight(cr);
cr.fight(dr);
cr.fight(cr);
}
[/CODE]

Andrei Alexandrescu''s book Modern C++ Design has more ways to do this, for example, with RTTI.

Share this post


Link to post
Share on other sites
Br1 - I think you should name your fight(dog) and fight(cat) functions differently, given that subject and object have been reversed in fight(animal).


“Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.”
— Brian W. Kernighan (C programming language co-inventor)

Share this post


Link to post
Share on other sites
Thanks for all the help, I see that I have found an interesting topic

I think I will start by reading up on double dispatch and dynamic casting, as I will eventually have many subclasses and that will make for combinatorial explosion otherwise.

Thanks again!

Share this post


Link to post
Share on other sites