-4

I am just wondering if the following C++ code guaranteed to work:

struct B1 {
    virtual void f() {};
};

struct B2 {
    virtual void f2() {};
};

struct D:public B1,public B2 {
};

int main() {
    D d;
    B1 *b1=&d;
    if (dynamic_cast<B2*>(b1)) {
      B2* b2 = reinterpret_cast<B2*>(b1); //is this conversion valid?
    };
    return 1;
};

Of course, you would why do i need this? Because i want to replace this:

C::C(B1* b): member(dynamic_cast<B2*>(b)?dynamic_cast<B2*>(b)->m():b) {};

with better construction (by performance, to not check type safety twice):

C::C(B1* b): member(dynamic_cast<B2*>(b)?reinterpret_cast<B2*>(b)->m():b) {};

Thanks in advance!

gena2x
  • 365
  • 2
  • 12
  • 7
    "Because i want to replace this (...) with something better (...)"? Your premise is wrong. – R. Martinho Fernandes Aug 15 '12 at 19:04
  • I'm trying to figure out what the type of `member` is that would make that last expression make any sense at all. – Mooing Duck Aug 15 '12 at 19:09
  • I thought C++ style casts were supposed to make things simpler to read :'( – John Humphreys Aug 15 '12 at 19:10
  • 2
    In which way is the second one better than the first? And please don't say performance. I'm not really one of the "anti-premature-optimization"-guys, but you don't mourn about the performance of a `dynamic_cast` when using things like virtual methods anyway, which bring more or less the same (negligable) performance-overhead (and are usually an even better approach than `dynamic_cast`s, aynway). – Christian Rau Aug 15 '12 at 19:11
  • 1
    possible duplicate of [When should static_cast, dynamic_cast and reinterpret_cast be used?](http://stackoverflow.com/questions/332030/when-should-static-cast-dynamic-cast-and-reinterpret-cast-be-used) – R. Martinho Fernandes Aug 15 '12 at 19:14
  • @ChristianRau - there's no `dynamic_cast` involved in a virtual function call. But a cross-hierarchy `dynamic_cast` like the one involved here is nasty (I once had to implement the runtime support for `dynamic_cast`). It has to search the type information tree, which can be quite extensive in more complicated inheritance hierarchies. I'd do pretty much anything to avoid having to do the same cast twice. – Pete Becker Aug 15 '12 at 19:26
  • @PeteBecker In fact in his case a `static_cast` would actually be the best solution (apart from looking for more natural ways to achieve his goal and avoiding the first `dynamic_cast` altogether). – Christian Rau Aug 15 '12 at 19:29
  • 1
    @ChristianRau - a `static_cast` won't work here. A `static_cast` can be used to move up or down in a hierarchy that's know to the compiler at the point of the cast. It won't do a cross-cast like the one at issue here. – Pete Becker Aug 15 '12 at 19:57
  • @PeteBecker Doesn't he cast inside the hierarchy here, since otherwise his `dynamic_cast` wouldn't have worked in the first place (and he wouldn't have searched for a better solution, but just a solution), or am I missing something here (I'm talking about this ternary operator construct, not the large example, of course)? – Christian Rau Aug 15 '12 at 20:12
  • 1
    @ChristianRau - "inside" the hierarchy is not the same as "up or down". A static cast only moves up or down, not sideways. So it can go from a base class to a derived class, or from a derived class to a base class, but not from a `B1*` to a `B2*`. That requires a runtime determination that the actual type of the object that the `B1*` points to is a derived type that is also derived from `B2`. – Pete Becker Aug 15 '12 at 20:19
  • @R. Martinho Fernandes - i made explanation better – gena2x Aug 15 '12 at 20:49
  • @Mooing Duck - it's for code instrumentation, idea is to add some instrumentation and not change constructor parameters – gena2x Aug 15 '12 at 20:51

2 Answers2

5

The solution to a software problem is often to add a level of indirection, in this case, a function. Assuming that the dynamic_cast's are supposed to be to B2* (not B1), write a function that does the right thing:

B1 *get_b(B1 *b) {
    B2 *b2 = dynamic_cast<B2*>(b);
    if (b2)
        return b2->m();
    else
        return b;
}

Then use that function in the initializer list:

C::C(B1 *b) : member(get_b(b)) { }
Pete Becker
  • 74,985
  • 8
  • 76
  • 165
  • This is not direct answer, but better approach. Thanks . – gena2x Aug 15 '12 at 20:47
  • @gena2x - sometimes the right answer is to unask the question. – Pete Becker Aug 15 '12 at 20:48
  • Unsure if i can follow this way, because this would require adding some kind of library to place this function, but still somehow i didn't thought about it =) – gena2x Aug 15 '12 at 20:55
  • @gena2x - you can make it an inline function, defined in the same header as the class that uses it. It could (and probably should) also be a static member function of that class. – Pete Becker Aug 15 '12 at 21:03
  • This "trick" supposed to be used multiple times across many classes, so, unfortunately, adding something to local translation unit would not help – gena2x Aug 15 '12 at 21:13
4

No, that's definitely not valid. All you can do safely with reinterpret_cast is cast it back to the original type; anything else is implementation defined.

Dirk Holsopple
  • 8,731
  • 1
  • 24
  • 37