我正在使用CRTP将D1
和D2
的常见实现转移到模板中,但是,在构造对象时,我必须调用特定于每种类型的重载函数。
以下代码的输出是
D 0x7ffc7d370538
D1 0
D 0x7ffc7d370540
D2 0
预期输出为
D 0x7ffc7d370538
D1 0x7ffc7d370538
D 0x7ffc7d370540
D2 0x7ffc7d370540
为什么dynamic_cast返回nullptr?如何修复此代码?
#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;
}
我发现的唯一解决方法是以下
#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;
}
但是,在我的场景中,代码重复太多,无法重复调用函数use
。例如,可以有许多派生类,或许多对类似于use
的函数的调用。
答案 0 :(得分:5)
造成麻烦的直接原因是,在构造派生类之前调用基类构造函数。因此,在构造函数中通过dynamic_class
进行强制转换会导致nullptr
。
没有办法解决,您不能使用基类构造函数派生类的对象。
另一方面,在同一类中同时使用运行时和编译时多态时,通常是设计气味。坚持其中任何一个。
答案 1 :(得分:0)
在此代码中
template <typename Derived>
B<Derived>::B() {
您将要初始化B<Derived>
的实例。实际上,这是在初始化B<D1>
实例的D1
基类子对象或B<D2>
实例的D2
基类子对象。
在成功创建基类子对象之后,D1
和D2
对象都不存在。这意味着在创建基类子对象期间,派生类对象还不存在,同样,基类对象 的动态类型不能为派生类型。
如果您想获得有关如何构造代码的建设性建议,则确实需要解释use
的实际用途。