0

I have a cpp code where in class c is derived from class b and class b is derived from class a.

Now class b has some public data member. So I am creating a instance of class c on heap passing its pointer to another class as pointer to a and there it is downcasting that pointer to pointer of class b and then printing public variables of class b.

Is this a valid downcasting. I am asking because just change of compiler has broken this working code.

I am including below code snippet which captures problem I am having.

#include <iostream>
using namespace std;


class grand
{
};
class parent : public grand
{
    public : parent(){i=0;}
    int i;
    parent(int j){ i = j;}
    void set(int j){i = j;}
};

class child : public parent{


public: child(){};
};

void print ( grand* ptr)
{
    parent *p = (parent*) ptr;
    std::cout << std::endl << p->i << std::endl;
}

int main() {
    // your code goes here
    child c;
    c.set(9);
    print(&c);
    return 0;
}

Thanks

user3494614
  • 603
  • 1
  • 7
  • 20
  • 1
    C-style casting should be avoided here. You should probably read up on [various casting techniques](http://stackoverflow.com/questions/28002/regular-cast-vs-static-cast-vs-dynamic-cast) and their applications. In this case you should change the definition of `print` to accept only `parent*` and let the compiler cast for you because you can't be guaranteed that your cast is valid otherwise. – tadman Sep 10 '14 at 15:33
  • Does your actual code use multiple inheritance by any chance? – Mark Ransom Sep 10 '14 at 15:37

3 Answers3

4

Is this a valid downcasting.

Yes. Your cast internally applies static_cast, which, according to §5.2.9/11, will give you the right result. If the argument for ptr doesn't point to a parent, the result of the cast is undefined - and so would the execution of the following code be.

Downcasting of polymorphic types in C++ works via dynamic_cast. Your grand class above isn't polymorphic - you have to add at least a virtual destructor to grand to make it polymorphic. Otherwise you'll get a compiler error with the following code.

parent *p = dynamic_cast<parent*>(ptr); // Once grand is polymorphic...

And check whether the result, p, is non-zero. Only this method reveals (at runtime) whether the cast worked! All others either invoke undefined behavior or undefined, non-zero values.

Some notes:

  • Downcasting is almost always a sign of bad design. Avoid it if possible, using - for example - virtual (print) functions.
  • print should take a pointer to const since it doesn't modify any data members.
Columbo
  • 60,038
  • 8
  • 155
  • 203
0

Your code, as written, is in fact valid, but there are a bunch of observations I'd like to make. Note that it's valid only because the object you pass to print is a parent or further derived class.

Then note that since you have to cast it the print function it's much safer to just change the function signature to take aparent instead of a grand and then you don't have to worry about the casting.

Then note that a likely cause of your problem is that in the file that does the cast, the compiler doesn't see the relationship between grand and parent so your C-style cast falls back to reinterpret_cast which is not what you want. If you can't change the signature of print at least change the cast to static_cast (or possibly dynamic_cast, but you can't do that in your example because the classes aren't polymorphic) so that the compiler will fail to compile when it can't see the class relationship.

Mark B
  • 95,107
  • 10
  • 109
  • 188
0

Instead of a C-style cast you should apply a dynamic_cast or a at least a static_cast if you compile without RTTI (runtime type information) for some reason.

Your C-style cast is the same as a reinterpret_cast, which essentially interprets the memory pointed to as if an object of type parent would have been constructed there. But, every compiler may have a different memory layout of derived classes, thus that may work in some circumstances but there's no guarantee.

bjhend
  • 1,538
  • 11
  • 25
  • Actually a C-style cast attempts a bunch of casts and `reinterpret_cast` is only the last resort. – Mark B Sep 10 '14 at 15:41
  • 2
    In this case, the C-style cast is equivalent to `static_cast`, since there is a valid downcast from `grand` to `parent`. But it should still be avoided; it would fall back to `reinterpret_cast`, giving bogus runtime results, where `static_cast` would give a useful compile-time error. – Mike Seymour Sep 10 '14 at 15:45