Runtime Type Checking

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Big Blue Ox

    #1

    Runtime Type Checking

    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_ty pe;
    };

    class Fish: public Pet
    {
    int water_temp;
    };

    class Kennel
    {
    list<Pet> bordered_pets;

    public:

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

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

    Kennel kennel;

    kennel.addPet(g erman_shepard);
    kennel.addPet(c allico);
    kennel.addPet(d almation);

    }

    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

  • Victor Bazarov

    #2
    Re: Runtime Type Checking

    Big Blue Ox wrote:[color=blue]
    > I am trying to store different types that are all derived from the same
    > base class in a list template.[/color]

    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.
    [color=blue]
    > So for instance lets say I have this is fragment of skeleton code:
    >[/color]

    The following is redacted a bit.
    [color=blue]
    > 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.p ush_back(pet); }
    > };
    >
    > main()[/color]

    int main()
    [color=blue]
    > {
    > Dog german_shepard;
    > Cat callico;
    > Dog dalmation;
    >
    > Kennel kennel;
    >
    > kennel.addPet(g erman_shepard);
    > kennel.addPet(c allico);
    > kennel.addPet(d almation);
    >
    > }
    >
    > 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?[/color]

    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_.
    [color=blue]
    > 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.[/color]

    Google for "heterogene ous container".

    V
    --
    Please remove capital As from my address when replying by mail

    Comment

    • roberts.noah@gmail.com

      #3
      Re: Runtime Type Checking


      Big Blue Ox wrote:
      [color=blue]
      > class Kennel
      > {
      > list<Pet> bordered_pets;
      >
      > public:
      >
      > void addPet(Pet& pet)
      > {
      > bordered_pets.p ush_back(pet);
      > }
      > };[/color]

      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.
      [color=blue]
      > 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.[/color]

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

      Others may have others.

      Comment

      • Jim Langston

        #4
        Re: Runtime Type Checking


        "Big Blue Ox" <eclecticguitar 2000@yahoo.com> wrote in message
        news:1138821794 .804551.254070@ o13g2000cwo.goo glegroups.com.. .[color=blue]
        > 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_ty pe;
        > };
        >
        > class Fish: public Pet
        > {
        > int water_temp;
        > };
        >
        > class Kennel
        > {
        > list<Pet> bordered_pets;
        >
        > public:
        >
        > void addPet(Pet& pet)
        > {
        > bordered_pets.p ush_back(pet);
        > }
        > };
        >
        > main()
        > {
        > Dog german_shepard;
        > Cat callico;
        > Dog dalmation;
        >
        > Kennel kennel;
        >
        > kennel.addPet(g erman_shepard);
        > kennel.addPet(c allico);
        > kennel.addPet(d almation);
        >
        > }
        >
        > 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[/color]

        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_ty pe;
        };

        class Fish: public Pet
        {
        int water_temp;
        };

        class Kennel
        {
        public:
        std::vector<Pet *> bordered_pets;
        void addPet(Pet* pet)
        {
        bordered_pets.p ush_back(pet);
        }
        void whatPet( int index )
        {
        if ( index >= bordered_pets.s ize() )
        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(g erman_shepard);
        kennel.addPet(c allico);
        kennel.addPet(d almation);
        kennel.addPet(g oldfish);
        kennel.addPet(c atfish);

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

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


        Comment

        • Jim Langston

          #5
          Re: Runtime Type Checking

          > The following compiles and runs. Notice: I used vector instead of list[color=blue]
          > 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_ty pe;
          > };
          >
          > class Fish: public Pet
          > {
          > int water_temp;
          > };
          >
          > class Kennel
          > {
          > public:
          > std::vector<Pet *> bordered_pets;
          > void addPet(Pet* pet)
          > {
          > bordered_pets.p ush_back(pet);
          > }
          > void whatPet( int index )
          > {
          > if ( index >= bordered_pets.s ize() )
          > 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(g erman_shepard);
          > kennel.addPet(c allico);
          > kennel.addPet(d almation);
          > kennel.addPet(g oldfish);
          > kennel.addPet(c atfish);
          >
          > for ( int i = 0; i < 5; ++i )
          > kennel.whatPet( i );
          >
          > std::string wait;
          > std::getline( std::cin, wait );
          > }[/color]

          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_ty pe;
          };

          class Fish: public Pet
          {
          int water_temp;
          };

          class Kennel
          {
          public:
          std::vector<Pet *> bordered_pets;
          void addPet(Pet* pet)
          {
          bordered_pets.p ush_back(pet);
          }
          void whatPet( int index )
          {
          if ( index >= bordered_pets.s ize() )
          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.b egin(); it !=
          bordered_pets.e nd(); ++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(g erman_shepard);
          kennel.addPet(c allico);
          kennel.addPet(d almation);
          kennel.addPet(g oldfish);
          kennel.addPet(c atfish);

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

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


          Comment

          • Big Blue Ox

            #6
            Re: Runtime Type Checking

            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

            Comment

            Working...