Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

dynamic_cast "this" to derived type: when is it legal?

Here is a code that obviously doesn't work, since downcasting "this" in a constructor is illegal:

#include <cassert>

class A {
protected:
        virtual ~A() {}
public:
        A();
};

class B : public A {
};

A::A() {
        assert(dynamic_cast<B*>(this));
}

int main(void) {
        B b;
        return 0;
}

As expected, when compiled with g++, the assertion fails.

Here is another code that, however, works (with g++ 4.7, at least, I haven't tried other compilers):

#include <cassert>

class A {
protected:
        virtual ~A() {}
public:
        A() {}
        void f();
};

class B : public A {
public:
        B() {
                f();
        }
};

void A::f() {
        assert(dynamic_cast<B*>(this));
}

int main(void) {
        B b;
        return 0;
}

My question is: is the second code "legal", i.e. can I expect that for any compiler it will work that way?

My intuition is that since f() is called from the body of B's constructor, "b" is already well formed as an instance of type B, which makes the code legal. Yet, I'm still kind of dynamic_casting "this" from a constructor...

(note that my question is not whether this is good practice or not, just if it's legal).

like image 208
sunmat Avatar asked Apr 29 '15 14:04

sunmat


2 Answers

Yes, the second example is well defined, and the cast will succeed. During the constructor of B, the dynamic type of the object is B, so a cast to B* will succeed.

In the first example, as you say, in the constructor of A the dynamic type is A, so a cast to B* will fail.

like image 190
Mike Seymour Avatar answered Oct 23 '22 19:10

Mike Seymour


My question is: is the second code "legal"

Yes, it's fine.

My intuition is that since f() is called from the body of B's constructor, "b" is already well formed as an instance of type B, which makes the code legal

It's legal anyway, but this is the reason the assert succeeds rather than failing: by the time you're in the body of B's constructor, you have an instance of type B

Yet, I'm still kind of dynamic_casting "this" from a constructor...

Note that A::f is statically well-formed wherever you call it from - it would just dynamically fail the assert if called from A::A. You could also instantiate an A and call f directly on it (since A isn't abstract) - that would still be well-formed, but would fail the assert.

like image 40
Useless Avatar answered Oct 23 '22 17:10

Useless