Runtime Type Checking

B

Big Blue Ox

Hello,

I am trying to store different types that are all derived from the same
base class in a list template.

So for instance lets say I have this is fragment of skeleton code:

class Pet
{
string name;
int feeding_times;
};

class Dog: public Pet
{
int play_time;
};

class Cat: public Pet
{
int kitty_litter_type;
};

class Fish: public Pet
{
int water_temp;
};

class Kennel
{
list<Pet> bordered_pets;

public:

void addPet(Pet& pet)
{
bordered_pets.push_back(pet);
}
};

main()
{
Dog german_shepard;
Cat callico;
Dog dalmation;

Kennel kennel;

kennel.addPet(german_shepard);
kennel.addPet(callico);
kennel.addPet(dalmation);

}

Now, if I want iterate through the list to check whether or not the
kennel list contains a class of type fish or not, how do I do this? Or
I guess a more general question is, is it legal to have a list of
different generic class types and if so how do I tell one apart from
another.

BBO
 
V

Victor Bazarov

Big said:
I am trying to store different types that are all derived from the same
base class in a list template.

You cannot store anything in a template. You can only store it in a class
object. It has to be a concrete class, so if you have a template, you got
to have an instantiation of it. Just so we use proper terminology.
So for instance lets say I have this is fragment of skeleton code:

The following is redacted a bit.
class Pet {};
class Dog: public Pet {};
class Cat: public Pet {};
class Fish: public Pet {};

class Kennel
{
list<Pet> bordered_pets;
public:
void addPet(Pet& pet) { bordered_pets.push_back(pet); }
};

main()

int main()
{
Dog german_shepard;
Cat callico;
Dog dalmation;

Kennel kennel;

kennel.addPet(german_shepard);
kennel.addPet(callico);
kennel.addPet(dalmation);

}

Now, if I want iterate through the list to check whether or not the
kennel list contains a class of type fish or not, how do I do this?

You don't. As soon as you [attempt to] store an object of a derived class
in a standard container instantiated on the base class, you get _slicing_.
> Or
I guess a more general question is, is it legal to have a list of
different generic class types and if so how do I tell one apart from
another.

Google for "heterogeneous container".

V
 
R

roberts.noah

Big said:
class Kennel
{
list<Pet> bordered_pets;

public:

void addPet(Pet& pet)
{
bordered_pets.push_back(pet);
}
};

inserting an item into a container copies that item. Your
bordered_pets list contains Pets, it does not contain Cats and Dogs.
You can fix this by having a list of pointers to Pet. You will likely
want a clone() method in your polymorphic types. There are many
different ownership strategies and you will need to pick one. The easy
way is probably to use boost's smart_ptr.
Now, if I want iterate through the list to check whether or not the
kennel list contains a class of type fish or not, how do I do this? Or
I guess a more general question is, is it legal to have a list of
different generic class types and if so how do I tell one apart from
another.

Ways to detect your type:
a) compare type_info.
b) attempt a dynamic cast
c) Pets has a "type" field.

Others may have others.
 
J

Jim Langston

Big Blue Ox said:
Hello,

I am trying to store different types that are all derived from the same
base class in a list template.

So for instance lets say I have this is fragment of skeleton code:

class Pet
{
string name;
int feeding_times;
};

class Dog: public Pet
{
int play_time;
};

class Cat: public Pet
{
int kitty_litter_type;
};

class Fish: public Pet
{
int water_temp;
};

class Kennel
{
list<Pet> bordered_pets;

public:

void addPet(Pet& pet)
{
bordered_pets.push_back(pet);
}
};

main()
{
Dog german_shepard;
Cat callico;
Dog dalmation;

Kennel kennel;

kennel.addPet(german_shepard);
kennel.addPet(callico);
kennel.addPet(dalmation);

}

Now, if I want iterate through the list to check whether or not the
kennel list contains a class of type fish or not, how do I do this? Or
I guess a more general question is, is it legal to have a list of
different generic class types and if so how do I tell one apart from
another.

BBO

The following compiles and runs. Notice: I used vector instead of list just
cause it was easier for me.

#include <iostream>
#include <string>
#include <vector>

class Pet
{
public:
virtual ~Pet() {};
private:
std::string name;
int feeding_times;
};

class Dog: public Pet
{
int play_time;
};

class Cat: public Pet
{
int kitty_litter_type;
};

class Fish: public Pet
{
int water_temp;
};

class Kennel
{
public:
std::vector<Pet*> bordered_pets;
void addPet(Pet* pet)
{
bordered_pets.push_back(pet);
}
void whatPet( int index )
{
if ( index >= bordered_pets.size() )
std::cout << "Bad Index" << std::endl;
else if ( typeid( *bordered_pets[index] ) == typeid( Dog ) )
std::cout << "it's a dog!" << std::endl;
else if ( typeid( *bordered_pets[index] ) == typeid( Cat ) )
std::cout << "It's a cat!" << std::endl;
else if ( typeid( *bordered_pets[index] ) == typeid( Fish ) )
std::cout << "It's a fish!" << std::endl;
else
std::cout << "I don't know what the heck this is!" << std::endl;
}
};

int main()
{
Dog* german_shepard = new Dog;
Cat* callico = new Cat;
Dog* dalmation = new Dog;
Fish* goldfish = new Fish;
Pet* catfish = new Fish;

Kennel kennel;

kennel.addPet(german_shepard);
kennel.addPet(callico);
kennel.addPet(dalmation);
kennel.addPet(goldfish);
kennel.addPet(catfish);

for ( int i = 0; i < 5; ++i )
kennel.whatPet( i );

std::string wait;
std::getline( std::cin, wait );
}
 
J

Jim Langston

The following compiles and runs. Notice: I used vector instead of list
just cause it was easier for me.

#include <iostream>
#include <string>
#include <vector>

class Pet
{
public:
virtual ~Pet() {};
private:
std::string name;
int feeding_times;
};

class Dog: public Pet
{
int play_time;
};

class Cat: public Pet
{
int kitty_litter_type;
};

class Fish: public Pet
{
int water_temp;
};

class Kennel
{
public:
std::vector<Pet*> bordered_pets;
void addPet(Pet* pet)
{
bordered_pets.push_back(pet);
}
void whatPet( int index )
{
if ( index >= bordered_pets.size() )
std::cout << "Bad Index" << std::endl;
else if ( typeid( *bordered_pets[index] ) == typeid( Dog ) )
std::cout << "it's a dog!" << std::endl;
else if ( typeid( *bordered_pets[index] ) == typeid( Cat ) )
std::cout << "It's a cat!" << std::endl;
else if ( typeid( *bordered_pets[index] ) == typeid( Fish ) )
std::cout << "It's a fish!" << std::endl;
else
std::cout << "I don't know what the heck this is!" << std::endl;
}
};

int main()
{
Dog* german_shepard = new Dog;
Cat* callico = new Cat;
Dog* dalmation = new Dog;
Fish* goldfish = new Fish;
Pet* catfish = new Fish;

Kennel kennel;

kennel.addPet(german_shepard);
kennel.addPet(callico);
kennel.addPet(dalmation);
kennel.addPet(goldfish);
kennel.addPet(catfish);

for ( int i = 0; i < 5; ++i )
kennel.whatPet( i );

std::string wait;
std::getline( std::cin, wait );
}

Ooops, I used new and I didn't use delete. This fixes that.


#include <iostream>
#include <string>
#include <vector>

class Pet
{
public:
virtual ~Pet() {};
private:
std::string name;
int feeding_times;
};

class Dog: public Pet
{
int play_time;
};

class Cat: public Pet
{
int kitty_litter_type;
};

class Fish: public Pet
{
int water_temp;
};

class Kennel
{
public:
std::vector<Pet*> bordered_pets;
void addPet(Pet* pet)
{
bordered_pets.push_back(pet);
}
void whatPet( int index )
{
if ( index >= bordered_pets.size() )
std::cout << "Bad Index" << std::endl;
else if ( typeid( *bordered_pets[index] ) == typeid( Dog ) )
std::cout << "it's a dog!" << std::endl;
else if ( typeid( *bordered_pets[index] ) == typeid( Cat ) )
std::cout << "It's a cat!" << std::endl;
else if ( typeid( *bordered_pets[index] ) == typeid( Fish ) )
std::cout << "It's a fish!" << std::endl;
else
std::cout << "I don't know what the heck this is!" << std::endl;
}
~Kennel()
{
for ( std::vector<Pet*>::iterator it = bordered_pets.begin(); it !=
bordered_pets.end(); ++it )
delete *it;
}

};

int main()
{
Dog* german_shepard = new Dog;
Cat* callico = new Cat;
Dog* dalmation = new Dog;
Fish* goldfish = new Fish;
Pet* catfish = new Fish;

Kennel kennel;

kennel.addPet(german_shepard);
kennel.addPet(callico);
kennel.addPet(dalmation);
kennel.addPet(goldfish);
kennel.addPet(catfish);

for ( int i = 0; i < 5; ++i )
kennel.whatPet( i );

std::string wait;
std::getline( std::cin, wait );
}
 
B

Big Blue Ox

Thanks for all the suggestions! You have all been very helpful to me. I
also just realized that this topic is covered extensively in
Stroustrup's Book; C++ Programming language... section 12.2.5 if anyone
else is interested.

Thanks again,
BBO
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,119
Latest member
IrmaNorcro
Top