Reputation:
I am using CRTP to move common implementation of D1
and D2
into template, however, when constructing object I have to make call to overloaded function specific to each type.
The output of the following piece of code is
D 0x7ffc7d370538
D1 0
D 0x7ffc7d370540
D2 0
while expected output is
D 0x7ffc7d370538
D1 0x7ffc7d370538
D 0x7ffc7d370540
D2 0x7ffc7d370540
Why dynamic_cast returns nullptr? How to fix this code?
#include <iostream>
template <typename Derived>
struct B {
B();
virtual ~B() {}
};
struct D1 : B<D1> {
};
struct D2 : B<D2> {
};
void use(D1* d) { std::cout << "D1 " << d << std::endl; }
void use(D2* d) { std::cout << "D2 " << d << std::endl; }
template <typename Derived>
B<Derived>::B() {
std::cout << "D " << this << std::endl;
Derived* derivedThis = dynamic_cast<Derived*>(this);
use(derivedThis);
}
int main() {
D1 d1;
D2 d2;
}
The only workaround which I found is the following
#include <iostream>
template <typename Derived>
struct B {
B();
virtual ~B() {}
};
struct D1;
struct D2;
void use(D1* d) { std::cout << "D1 " << d << std::endl; }
void use(D2* d) { std::cout << "D2 " << d << std::endl; }
struct D1 : B<D1> {
D1() { use(this); } # code duplication
};
struct D2 : B<D2> {
D2() { use(this); } # code duplication
};
template <typename Derived>
B<Derived>::B() {
std::cout << "D " << this << std::endl;
}
int main() {
D1 d1;
D2 d2;
}
However in my scenario it is too much code duplication to repeat call to function use
. For example, there can be many derived classes, or many calls to functions similar to use
.
Upvotes: 0
Views: 94
Reputation: 67772
In this code
template <typename Derived>
B<Derived>::B() {
you're about to initialize a instance of B<Derived>
. In practice, this is initializing either the B<D1>
base-class subobject of a D1
instance, or the B<D2>
base-class subobject of a D2
instance.
Neither the D1
nor the D2
object can exist until after the base-class subobject has been successfully created. This means that during creation of the base-class subobject, the derived-class object cannot yet exist, and likewise the dynamic type of your base-class object cannot yet be the derived type.
If you want constructive suggestions on how to structure your code instead, you really need to explain what use
is really supposed to do.
Upvotes: 0
Reputation: 62603
The immediate cause of your troubles is the fact than base class constructors are called before derived classes are constructed. Because of that, casting through dynamic_class
in constructor leads to nullptr
.
There is no way around it, you can't use an object of derived class from base class constructor.
On a side note, usually it is a design smell when both runtime and compile-time polymorphism are used in the same class. Stick to either of them.
Upvotes: 5