Find the answer to your Linux question:
Results 1 to 6 of 6
Hi Im fairly new to c++. There must be a better way to do the following?:- Say I have a base class, Pet. I have several child classes that extend ...
Enjoy an ad free experience by logging in. Not a member yet? Register.
  1. #1
    Just Joined!
    Join Date
    Mar 2006
    Posts
    42

    c++ Casting base class to child class?


    Hi

    Im fairly new to c++. There must be a better way to do the following?:-

    Say I have a base class, Pet. I have several child classes that extend from this, like Dog, Cat, Fish etc.

    I have the following function, that returns a pointer to a new Pet:-

    Code:
    Pet* addPetToVet()
    {
            //Do some stuff
            return new Pet();
    }
    This will return a pointer an instance of a pet object.

    now, if I want to interprete this pet as a dog or cat I have to do this:-

    Code:
    Dog* dogA = static_cast<Dog*>(addPetToVet());
    Cat* catA = static_cast<Cat*>(addPetToVet());
    Is there a way around this? Casting seems lame. I cant write a function for each type of pet...

    thanks

    Joe

  2. #2
    Linux Newbie tetsujin's Avatar
    Join Date
    Oct 2008
    Posts
    117
    Quote Originally Posted by Joe2003 View Post
    Hi

    Im fairly new to c++. There must be a better way to do the following?:-

    Say I have a base class, Pet. I have several child classes that extend from this, like Dog, Cat, Fish etc.

    I have the following function, that returns a pointer to a new Pet:-

    Code:
    Pet* addPetToVet()
    {
            //Do some stuff
            return new Pet();
    }
    This will return a pointer an instance of a pet object.

    now, if I want to interpret this pet as a dog or cat I have to do this:-

    Code:
    Dog* dogA = static_cast<Dog*>(addPetToVet());
    Cat* catA = static_cast<Cat*>(addPetToVet());
    Is there a way around this? Casting seems lame. I cant write a function for each type of pet...
    I don't know what your "Cat" and "Dog" classes look like - but as it stands there's nothing that makes it clear that the result of addPetToVet() even is a cat or dog. If Cat or Dog have extra data fields that Pet doesn't, the result of working with the dogA pointer could be that you wind up clobbering the next thing in memory after the Pet you created with addPetToVet().

    Basically, if you're going to static_cast<> a pointer, you should be sure that the pointer points to an object of the type you're casting to. You shouldn't cast it to Dog* unless you're sure it was allocated as a new Dog or a child class of Dog.

    (Of course, if you are sure that the memory footprint of class Dog is no different than the memory footprint of class Pet, it can be safe, even useful to allocate as Pet and cast to Dog - you just have to be careful that you get it right...)

    If your classes have virtual methods (and they probably should - otherwise what's the point of storing them as base class pointers?) you can use dynamic_cast<>. The nice thing about dynamic_cast<> is that it does runtime type checking. So if you have a Cat* (stored as a Pet*) and you try to dynamic_cast<> it to Dog*, the cast will return zero, because the type is incompatible. You can use this to determine the type of a base class pointer.

    As for creating the Pet*'s, why not just call "new Dog(...)" or "new Cat(...)" as needed? If there's some bit of extra work that needs to be done upon construction, the constructor can call that code...

  3. #3
    Linux Guru Rubberman's Avatar
    Join Date
    Apr 2009
    Location
    I can be found either 40 miles west of Chicago, in Chicago, or in a galaxy far, far away.
    Posts
    11,709
    You can't use static casts for this. You need to use the dynamic_cast<type>() method. It will return a null pointer if it can't do the up-cast as necessary from Pet* to Dog* or Cat*. IE:
    Code:
    Pet* pPet = addPetToVet();
    Dog* pDog = dynamic_cast<Dog*>(pPet);
    if (!pDog)
    {
        cout << "Not a dog!" << endl;
    }
    So, this would be acceptable in code where you only know you are getting a pointer to a pet, but you don't know what kind of pet it may be. This is where using RTTI (runtime type information) is helpful, so you can do an isA(Dog) or isA(Cat) type of query on a Pet object. Anyway, this is a common sort of problem when you are dealing with a polymorphic domain. There are multiple approaches to solving this problem, and none of them are optimal in C++, in my experience (20 years C++ programming).

    Final note. Remember, if you use dynamic_cast<type*> with a pointer, it will either return nil, or a pointer to the specified. If you use it with a reference, as in dynamic_cast<type&>, it will either return a reference of the correct type, or throw a bad_cast exception.

    Ultra-final note. You can use static_cast<> when casting from a derived to a base class, or from a non-virtual base class to a derived class. Because it is unchecked at runtime, it is faster than dynamic_casts<>. However, it cannot be used to cast from a virtual base class (such as Animal, which may be virtual base class for Pet, Livestock, etc) to a derived class. For that you need to use dynamic_cast<>, which IS runtime checked. So, in the final analysis, know what you really intend, and beware of the Law of Unintended Consequences...
    Sometimes, real fast is almost as good as real time.
    Just remember, Semper Gumbi - always be flexible!

  4. $spacer_open
    $spacer_close
  5. #4
    Linux Newbie tetsujin's Avatar
    Join Date
    Oct 2008
    Posts
    117
    Quote Originally Posted by Rubberman View Post
    You can't use static casts for this.
    Well, you can use static cast to change a parent-class pointer to a child-class pointer... In the case of pointer types or references, as long as there's a path up or down the class hierarchy from the original type to the new type, static_cast can make the conversion. The trick is you just need to be sure that this conversion is safe before you attempt it.

    One relatively safe example would be something like this:

    Code:
    BaseClass* x;
    ...
    if (dynamic_cast<DerivedClass1*>(x)) {
        DerivedClass1& y = static_cast<DerivedClass1&>(x);
        ....
    } else if (dynamic_cast<DerivedClass2*>(x)) {
        DerivedClass2& y = static_cast<DerivedClass2&>(x);
        ....
    } else if (dynamic_cast<DerivedClass3*>(x)) {
        DerivedClass3& y = static_cast<DerivedClass3&>(x);
        ....
    }
    In that case, dynamic_cast() is just being used to make sure the static_cast() operation will be safe... And the static_cast() is used to avoid doing the runtime type check more than once.

    You can also use static_cast<> to convert to a child class in cases where you can be sure the child class introduces no additional member variables. For instance, if you call a function that returns a pointer to an object of class A, you could introduce methods to that object by creating a class B which derives from class A, adding the new method there, and doing a static_cast(). Though usually there should be no need for something like that...

  6. #5
    Just Joined!
    Join Date
    Dec 2008
    Posts
    8
    As per my understanding, the dynamic_cast in shown below code snippet will hold valid when the Base pointer holds the Derived class object.

    Code:
    Base *b;
    ..
    Derived *d = dynamic_cast<Derived*>(b);
    ..
    Please let me know if my understanding is wrong.

    Thanks.

    Regards,

    ~Praveen.

  7. #6
    Linux Guru Rubberman's Avatar
    Join Date
    Apr 2009
    Location
    I can be found either 40 miles west of Chicago, in Chicago, or in a galaxy far, far away.
    Posts
    11,709
    Quote Originally Posted by praveen_kumar View Post
    As per my understanding, the dynamic_cast in shown below code snippet will hold valid when the Base pointer holds the Derived class object.

    Code:
    Base *b;
    ..
    Derived *d = dynamic_cast<Derived*>(b);
    ..
    Please let me know if my understanding is wrong.

    Thanks.

    Regards,

    ~Praveen.
    Yes, that is the case. If Derived <- Base, then a dynamic cast of the Base* to a Derived* will be either null if Base is not of type Derived, otherwise it is a valid pointer to the Derived object. You can up or down cast with dynamic_cast<T*> this way. It will adjust the pointer address in cases like this:
    Code:
    class Base1 {
    int member1;
    .
    .
    .
    };
    
    class Base2 {
    int member2;
    .
    .
    .
    };
    
    class Base3 : public Base1, public Base2 {
    int member3;
    .
    .
    .
    };
    
    class Base4 : public Base1 {
    .
    .
    .
    };
    
    class Derived : public Base3 {
    .
    .
    .
    };
    
    void somecode()
    {
         Base1* p1;
         Base2* p2;
         Base3* p3;
         Base4* p4;
         Derived* d1;
    
         p1 = new Derived;  // Fine - Derived is a kind of Base1, Base2, and Base3;
         p2 = dynamic_cast<Base2*> p1; // Fine - p1 is actually a Derived object, which is a kind of Base2
         p3 = dynamic_cast<Base3*> p2  // Fine, for the same reasons, but p2 <> p3 because Base2
                                                             // is offset from the root of Base3..
         p4 = dynamic_cast<Base4*> p1; // FAIL - Derived is not a kind of Base4 object so p4 == 0.
         d1 = dynamic_cast<Derived*> p2; // Fine, but because Base2 is offset from the root, d1 <> p2.
    }
    Anyway, the neat thing about dynamic_cast<T> is that it looks at the RTTI (Run-Time Type Information) built into the classes and uses that to figure out what is the right thing to do.
    Sometimes, real fast is almost as good as real time.
    Just remember, Semper Gumbi - always be flexible!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •