views:

124

answers:

6

For instance I have code like that

class Base1
{
  virtual void wonderFULL() = 0;
};

class Base2
{
  // all this weird members
};

class Derived : public Base1, public Base2
{
  // not so weird members
};

int main()
{
  Derived Wonder;
  magicFunction(&Wonder);
  return 0;
}

void magicFunction(Base2 *ptr)
{
  if (Base1 *b1 = dynamic_cast<Base1 *>(ptr))
    b1->wonderFULL();
}

However wonderFULL is never executed due to impossibility to cast ptr to b1. Is it possible at all to perform such a conversion?

A: 

Going by what I understand of the way some C++ compilers arrange the class hierarchy in memory it should be possible to cast from one base class to another, but you have to first cast to the derived class.

Therefore you would need to do something like:

Base1* b1 = dynamic_cast<Derived*>(ptr);

This casts the given pointer ptr to the derived class, and then it gets implicitly cast to its other base class pointer.

However another easier way to do this would be to just have a method in the Base2 class that returns a Base1 pointer, and the derived class can implement this itself without any tricky code. (The same function in Base2 can just return NULL if you don't want a pure virtual class).

Daemin
A: 

I'm not really big in C++, but reinterpret_cast pretty much casts anything to anything, right?

Besides, in your case you could implement your magicFunction as

void magicFunction(Base2 *ptr) { 
    if (Derived *d = dynamic_cast<Base1 *>(ptr)) 
        d->wonderFULL(); 
}

Does this help?

Here Be Wolves
Which is one reason why it shouldn't be used...the other being that it doesn't work for casting across MI hierachies... `-1`
sbi
+5  A: 

This

#include <iostream>

class Base1 {
public:
    virtual void wonderFULL() = 0;
};

class Base2 {
public:
    virtual ~Base2() {}                                       // added so the code compiles
};

class Derived : public Base1, public Base2 {
    virtual void wonderFULL() {std::cout << "wonderful\n";}   // added so the code compiles
};

void magicFunction(Base2 *ptr) {
    if (Base1 *b1 = dynamic_cast<Base1 *>(ptr))
        b1->wonderFULL();
}

int main() {
    Derived Wonder;
    magicFunction(&Wonder);
    return 0;
}

prints wonderful for me. My conclusion is that you're not showing the code necessary for your problem to reproduce.

Take (a copy of) your actual code and by removing uneccessary code step by step distill it until you derive at a self-contained (needs no other headers except from the std lib), compilable example that reproduces the problem. Very likely you will find the problem while doing so. However, if you don't, you have the perfect repro case to come back here and ask about.

sbi
This code isn't what the OP posted. (Note how you have a virtual function in Base2 which allows the dynamic_cast.)
Bill
@Bill: Yes, of course. Otherwise the compiler won't even compile the code. See my note at the end of my answer.
sbi
+1, one can't cast to a pointer to class A if class A has no virtual member functions.
sharptooth
@sbi: I assumed that the real problem was that the OP didn't have a virtual function in one of the base classes. Hard to tell for sure though. :)
Bill
@Bill: Yeah, it might be that there's a compiler out there that doesn't issue a diagnostic for that. It's hard to imagine, though.
sbi
@sbi: To be fair, it was not immediately obvious to me what `cannot dynamic_cast ‘ptr’ (of type ‘class Base2*’) to type ‘class Base1*’ (source type is not polymorphic)` meant, either. On the other hand, google knows that one.
Bill
+2  A: 

You can cast up the hierarchy then back down:

void magicFunction(Base2& ptr)
{
    try
    {
        Derived&  d = dynamic_cast<Derived&>(ptr);
        Base1&    b = dynamic_cast<Base1&>(d);
        b.wonderFULL();
    }
    catch(const std::bad_cast&)
    { /* Cast failed */ }
}
Martin York
That shouldn't be necessary with `dynamic_cast`. See my answer.
sbi
It documents intent. If the compiler optimizes it away fine. But the extra human readable documentation of entente is good for me.
Martin York
@Martin: (You should properly @address...) Whether documenting the intent this way is necessary is open to debate. The original qwuestion ("Is it possible to dynamic_cast from one base class to another?") should have a clear and simple answer.
sbi
@sbi I'd give my right arm for documenting intent when dealing with any casting calls other than static_cast. There's people that write code for others and then there's a whole world of people who don't.
wheaties
@wheaties: Everyone loves good documentation, but _what is_ good documentation isn't universally agreed upon. What you say isn't an objective criterion: Some newbie might want to write `i = i + 1` to document their intention, and consider `++i` to concise. In the same vein I can very well imagine myself looking at this roundabout way to do a cast across a MI hierarchy and wondering why on earth it is done that way and what I am missing. But I didn't want to take sides in this discussion. Readability is, to some extent, subjective. The answer to the question asked isn't: it's "Yes, it is."
sbi
+2  A: 

You have some syntax errors, but your real problem is dynamic_cast won't work properly if your base classes don't have at least one virtual function.

If you make it look like:

class Base2
{
public:
  virtual ~Base2() {}
  // all this weird members
};

And then fix your other errors: wonderFULL is private, and never defined. magicFunction is declared after it is used.

Then everything works.

Bill
A: 

I've found the problem. It was not about dynamic_casts. I was checking wrong object which was not inherited from abstract base. Thanks.

Alex