Casting question

Hi programmers...

I have a problem that is twisting my mind a lot...

I'm working on a program called "Animal Shelter", that will hold Cats and Dogs using Lists. I have created the Class Animal and its child classes Dog and Cat.
Suppose I want to create the method "Enqueue" which will enqueue to a list (Called Cats and Dogs), an Animal a, that could be either a Cat or a Dog. I've been able to determine how to perform an equivalent to Java's "instanceof" to determine if the Animal a is a Dog or a Cat, however, I've not been able to perform a cast on the Animal a, to allow the program to interpret it as a Dog or a Cat.

1
2
3
4
5
6
7
void enqueue(Animal a)
	{
		if(typeid(Cat)==typeid(a))
		{
			Cats.push_back(dynamic_cast<Cat*>(a)); //error on this line
		}
	}


I'm new on this so I will appreciate your help on this matter,

Cheers!
Using dynamic_cast to convert a base pointer to a derived pointer only works if your classes are polymorphic. Do you have virtual methods in Animal, that are overridden by Cat?

Oh... just noticed - you're trying to cast an object to a pointer. You want:

Cats.push_back(dynamic_cast<Cat*>(&a));

so that you're casting a pointer to a pointer.

Edit: Although in the code you've posted, a is effectively a local object, as you're passing the Animal into enqueue by value, not reference. This means that as soon as the function exits, the object is destroyed, and the pointer in the Cats vector will be pointing to invalid memory.
Last edited on
@MikeyBoy: you are right, I haven't any virtual method. Doing some googling I found that I need a static_cast... The program works now and looks like this:

1
2
3
4
5
6
7
8
if(typeid(Cat)==typeid(a))
		{
			Cats.push_back(static_cast<Cat&>(a));
		}
		else
		{
			Dogs.push_back(static_cast<Dog&>(a));
		}

My code works, however the if condition is not working since the typeid of Cat is Cat and the typeid of a is Animal... I want to retrieve the derived type of animal... it should be Cat or Dog... any suggestions???

Thanks for your answer by the way
Last edited on
check out object slicing
You need to ask for a reference or a pointer to an `Animal'
you are right, I haven't any virtual method. Doing some googling I found that I need a static_cast... The program works now and looks like this:

If you're still passing an Animal by value, that code is wrong. An Animal can never be a Cat or a Dog.


I've been able to determine how to perform an equivalent to Java's "instanceof" to determine if the Animal a is a Dog or a Cat,

As I understand it, instanceof will evaluate to true if the base class occurs anywhere downstream of the derived class for. typeid only extracts the most-derived type, so the two are not exactly equivalent, even though they may seem so in this simple example. So, if you were to further derive from Cat or Dog code like this would get very ugly, very quickly.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <cstdlib>
#include <typeinfo>
#include <ctime>
#include <iostream>
#include <list>

class Animal
{
public:
    virtual ~Animal() = 0 ;
};

Animal::~Animal() {}

class Cat : public Animal
{
};

class Dog : public Animal
{
};

typedef std::list<Animal*> list_type;

void displayTypes(list_type::iterator beg, list_type::iterator end)
{
    while (beg != end)
    {
        Animal* value = *beg++;

        if (typeid(*value) == typeid(Cat))
            std::cout << "Cat";
        else if (typeid(*value) == typeid(Dog))
            std::cout << "Dog";
        else if (typeid(*value) == typeid(Animal))
            std::cout << "Animal";          // This should never happen!
        else
            std::cout << "Unknown";

        std::cout << '\n';
    }
}

int main()
{
    std::srand(std::time(0));

    list_type list;

    for (unsigned i = 0; i < 10; ++i)
        list.push_back((rand() % 2 ? (Animal*)new Cat : (Animal*)new Dog));

    displayTypes(std::begin(list), std::end(list));

    while (!list.empty())
    {
        delete list.back();
        list.pop_back();
    }
}


http://ideone.com/ktgLoX
Thanks cire and ne555 for your advices.

My code looks like this right now:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include <iostream>
#include <list>

using namespace std;

class Animal
{
private:
	string name;
	int order;
public:
	Animal(string n) : name(n) {}
	void setOrder(int ord) {order=ord;}
	int getOrder() {return order;}
	bool isOlderThan(Animal a)
	{
		return  this->order<a.getOrder();
	}
	string getName() {return name;}
};

class Dog : public Animal
{
public:
	Dog(string n) : Animal(n) {}
};

class Cat : public Animal
{
public:
	Cat(string n) : Animal(n) {}
};


class animalQueue
{
	list<Cat> Cats;
	list<Dog> Dogs;
private:
	int order=0; 
public:
	void enqueue(Animal a)
	{
		a.setOrder(order);
		order++;
		
		if(typeid(a)==typeid(Cat)) //program cannot differentiate if a is a cat or a dog...
		{
			Cats.push_back(static_cast<Cat&>(a));
		}
		else
		{
			Dogs.push_back(static_cast<Dog&>(a));
		}
	}
	
	Dog dequeueDogs()
	{
		Dog dog_out = Dogs.front();
		Dogs.pop_front();
		return dog_out;
	}
	
	Cat dequeueCats()
	{
		Cat cat_out = Cats.front();
		Cats.pop_front();
		return cat_out;
	}
	
	Animal dequeueAny()
	{
		if(Dogs.size()==0) return dequeueCats();
		else if(Cats.size()==0) return dequeueDogs();
		
		Dog dog_aux = Dogs.front();
		Cat cat_aux = Cats.front();
		
		if(dog_aux.isOlderThan(cat_aux)) return dequeueDogs();
		else return dequeueCats();
	}
};

int main(int argc, const char * argv[])
{
	animalQueue aq;
	aq.enqueue(Dog("waffles"));
	aq.enqueue(Dog("growls"));
	aq.enqueue(Cat("meow"));
	aq.enqueue(Cat("dolly"));
	aq.enqueue(Dog("woof"));
	
	Dog dt=aq.dequeueDogs();
	cout<<dt.getName()<<endl;
	aq.dequeueDogs();
	aq.dequeueCats();
	aq.dequeueAny();
	return 0;
}


The problem here is the enqueue function inside animalQueue class. I cannot differentiate if the animal a received as parameter is a cat or a dog. Everything else is working fine. Any suggestions?

Cheers!
Last edited on
The problem here is the enqueue function inside animalQueue class. I cannot differentiate if the animal a received as parameter is a cat or a dog. Everything else is working fine. Any suggestions?

Several of us have already told you about the problem that's causing this, but let's say it one more time:

You're passing your Animal into enqueue by value. This means that you're slicing it, so that, inside enqueue, you don't have a Dog or a Cat any more - you just have an Animal.

You need to pass in a reference or a pointer to enqueue.
@MikeyBoy: Got it. Can't be more clear than that.

Now I'm struggling with the references/pointers... Suppose the following:

1
2
3
4
5
6
int main(int argc, const char * argv[])
{
	animalQueue aq;
	Dog* waffles=new Dog("waffles");
	aq.enqueue(waffles);
}


I have created a Dog pointer and I'm sending it to enqueue function.

1
2
3
4
5
6
void enqueue(Animal* a)
	{
		a->setOrder(order);
		order++;
		if(typeid(a)==typeid(Dog)) cout<<"It's a Dog<<endl;
        } 


Enqueue receives and Animal pointer since such animal could be a Cat or a Dog. In this case I sent a Dog pointer to the function... then why the program doesn't interpret the the object I'm sending as a Dog? What can I do to let the program know it is going to receive a Cat or a Dog and interpret as such?

Thanks and I'm sorry if I sound clumsy but I'm a beginner on this.

Cheers!
I haven't really been following this thread... so forgive me if I repeat what has already been said. But there are a few things here that stand out to me that need to be addressed.


The biggest of which is that what you are trying to do is "wrong". Or at least, it's very likely you are using your classes incorrectly.

The whole point of having an abstract base class (in this case, Animal) is so that you can treat ALL animals the same. Checking to see whether or not this particular Animal is a Dog is pointless. With a proper design, your code should not care what kind of animal it is dealing with. It should be able to work with any of them.

That said... there are certainly occasions where you'll need to do this... but they are very rare... and I'm all but certain you do not need to do them here.


The common alternative is to use virtual functions to differentiate which type you have. IE:

1
2
3
4
5
6
7
8
9
10
11
12
class Animal
{
//...
    virtual void announce() = 0;
};

//...
class Dog : public Animal
{
//...
    virtual void announce() { cout << "I'm a dog."; }
};


Since the announce function is virtual, when you call it, it will automatically (and very quickly) figure out what type of animal it is, and call that animal's specific announce function. So Dogs, Cats, Birds, etc can all announce differently... but code which uses them can just call a generic announce function without having to care what specific kind of Animal they have.



The general rule here is... if you have to downcast... you're doing it wrong.


EDIT:

Another thing is this:

1
2
3
4
5
6
void enqueue(Animal* a)
	{
		a->setOrder(order);
		order++;
		if(typeid(a)==typeid(Dog)) cout<<"It's a Dog<<endl; // <- wrong
        }  


'a' is of type Animal* because that's how it was defined. It will never be of type Dog so that if block will never execute.

*a could be of type Animal or of any derived type. So the correct comparison here would be:

if( typeid(*a) == typeid(Dog) )

But again.. you should not be using typeid this way anyway. This is the wrong way to approach this problem.
Last edited on
@Disch: Thank you very much!!! I was trying to imitate the functionality of Java's "instanceof" function but after all the comments here and some others I found I realize going this path wasn't the best approach. I corrected my program the way you describe and it works. The code structure is different though, but the important thing is that works :)

Thanks a lot to all who guided me on this topic !!!

Cheers!
Last edited on
Forgive me for adding my 1 cent worth amongst those who have vastly more experience than me, and I hope I am not going over what is already understood by the OP.

I am probably saying what others have said in a slightly different way - hopefully it is useful.

If a function is virtual and is declared with a parameter that is a pointer or reference to a base class (animal), but called with an argument that is a pointer or reference to a derived class (dog), then the complier will do the right thing. This works even when the virtual function is defined once in the base class, because the compiler uses the virtual table (vtable) to navigate up the class tree, until it finds a function it can use.

So you could define the enqueue & dequeue functions once in the Animal class - it would have pointers to Animal and AnimalQueue as parameters. We need AnimalQueue as a parameter so we know which object to put the animal pointer into. The AnimalQueue class has a container which is (not surprisingly) a Queue of Animal pointers. When you call the enqueue function, you send it a pointer to Dog, Cat or Bird, or whatever. Then you can use the pointers in the AnimalQueue container to use that particular animals interface. But keep the interface general (as Disch was saying with the announce function)

I wonder whether it is worth each class having it's own virtual Type function which would return a "Cat" or "Dog" value that had been set in the constructor. That way you could administer animal specific medication say, by testing the value returned by that function. I think this is better than casting or typeid'ing and also might have been what Disch was alluding to.

This whole thing is a very powerful & useful thing in polymorphism, because we can have one EnQueue function, as opposed to EnQueueDog, EnQueueCat etc. And there is only one data container for all types, not a container for each type.

Hope all is well :+)
I'm not sure to follow it, ¿mind to show an example?
@ne555

So you are a smart experienced programmer - which part of my explanation did you not follow :+) ?

Regards
I wonder whether it is worth each class having it's own virtual Type function which would return a "Cat" or "Dog" value that had been set in the constructor. That way you could administer animal specific medication say, by testing the value returned by that function. I think this is better than casting or typeid'ing and also might have been what Disch was alluding to.


The only time I can imagine this approach being useful is for object serialization. And I doubt that's what OP is doing (or that he cares about it). And even in that case, such a function shouldn't be public but should be restricted to just the child class and maybe a factory class. It definitely should not be called by outside code.


The goal with using an abstract class is so that you can write code which works with all derived types. The benefit of this is that writing this code allows you to add new derived types in the future without having to change any of your existing code.

If you start writing "if this Animal is a Dog" code, you destroy that ability. Now instead of just adding a new derived class which implements the necessary virtual functions... you now have to go back to all those if-Animal-is-Dog blocks to add your new type there as well... which might be scattered across dozens of source files.


So yeah... if you have an Animal pointer... assume it can be ANY kind of Animal and treat it as such. Only do things with it that can be done with any Animal. Don't try to determine which type of Animal it is. If you need to do things that are specific to Dogs, then you should not have an Animal pointer, you should have a Dog pointer... and you should not have to downcast to obtain that pointer.


Again.. there are going to be exceptions to this rule... but they're very rare. I'm sure the OP has no need for downcasting and/or type identification.
@Disch

Yeah, I was going a bit far (wrongly) with the part you quoted, and I can see how messy that would be. I could have given an example of a virtual function in the Animal class, like Feed(). This function could be over-ridden in an appropriate way where necessary for derived classes - Dogs, Cats, Birds, Elephants etc get their own types & amounts of food .

This still fits in with:

if you have an Animal pointer... assume it can be ANY kind of Animal and treat it as such.


Any way, thanks for your always useful info. Cheers
> So you could define the enqueue & dequeue functions once in the Animal class
> - it would have pointers to Animal and AnimalQueue as parameters
That part, ¿how would be the implementations in `Animal', `Cat' and `Dog', and how would you use it?
@ne555

Sorry for the late reply, have been a bit busy.

Realised that If one was going to have a AnimalQueue class, the enqueue & dequeue functions belong with it, not in the Animal class. The functions would take a pointer or reference to Animal as a parameter. They would be called with Cat or Dog ptr or ref, as required. They wouldn't need to be virtual, because there is no inheritance for that class - it's just a simple container.

I need to keep reminded myself to be careful in what I say.
Topic archived. No new replies allowed.