当你 dynamic_cast 在具有相同基数 class 的派生 class 之间时会发生什么?
What happens when you dynamic_cast between derived classes with the same base class?
我想弄清楚当你 dynamic_cast
从一个派生 class 到另一个派生 class 时会发生什么。为什么下面的代码会引发分段错误?请注意,我并没有尝试将此代码用于任何事情。我只是想了解发生了什么。
还值得注意的是,使用 static_cast
也可以使用相同的代码。我似乎找不到任何文档来详细说明这里发生的事情。有人可以解释一下吗?
struct base
{
virtual void printing(){cout<<"base printing"<<endl;};
};
struct derived_1 :public base
{
virtual void printing(){cout<<"derived_1 printing"<<endl;};
};
struct derived_2 :public base
{
virtual void printing(){cout<<"derived_2 printing"<<endl;};
};
int main()
{
base * b = new derived_2();
derived_1 *d_1 = dynamic_cast<derived_1*>(b);
// calling printing raises segmentation fault
d_1->printing();
}
转换为 derived_1
将失败,因为 derived_2
是一个 base
对象但 不是 一个 derived_1
对象。因此,您无法 "side cast" 指向所需的指针类型。
并不是说每当 dynamic_cast
失败时,它都会 return 一个 nullptr
(except for reference types)。这最终会导致您的代码出现分段错误(一般来说,我建议您在使用动态转换的对象之前总是添加一个 if (d_1 != nullptr)
)。
更新:
顺便说一句,这实际上是dynamic_cast
必要性的一个很好的例子。即使您可能想在您的示例中使用 static_cast
并且它会编译,您将处理 未定义的行为 。使用 static_cast
将编译而不会出现问题,但您实际上会使用损坏的类型。假设 derived_1::printing()
访问一些变量 derived_1::a
,它在 derived_2
中不存在。通过将 derived_2
对象(没有 a
)静态侧投到 derived_1
对象 d_1
,您会错误地假设 d_1
包含一些有效a
,事实并非如此
示例:
// ...
struct derived_1 :public base
{
const int a = 123;
void printing() override {cout<<"derived_1 printing " << endl;}
void foo() { cout << "Foo using constant = " << a << endl; }
};
// ...
int main()
{
base * b = new derived_2();
derived_1 *d_1 = static_cast<derived_1*>(b);
d_1->printing(); // Will call derived_2::printing(), which is not what you expect!
d_1->foo(); // Won't show a = 123 but some nonesense (mostly 0),
// because a is not defined in derived_2.
}
我想弄清楚当你 dynamic_cast
从一个派生 class 到另一个派生 class 时会发生什么。为什么下面的代码会引发分段错误?请注意,我并没有尝试将此代码用于任何事情。我只是想了解发生了什么。
还值得注意的是,使用 static_cast
也可以使用相同的代码。我似乎找不到任何文档来详细说明这里发生的事情。有人可以解释一下吗?
struct base
{
virtual void printing(){cout<<"base printing"<<endl;};
};
struct derived_1 :public base
{
virtual void printing(){cout<<"derived_1 printing"<<endl;};
};
struct derived_2 :public base
{
virtual void printing(){cout<<"derived_2 printing"<<endl;};
};
int main()
{
base * b = new derived_2();
derived_1 *d_1 = dynamic_cast<derived_1*>(b);
// calling printing raises segmentation fault
d_1->printing();
}
转换为 derived_1
将失败,因为 derived_2
是一个 base
对象但 不是 一个 derived_1
对象。因此,您无法 "side cast" 指向所需的指针类型。
并不是说每当 dynamic_cast
失败时,它都会 return 一个 nullptr
(except for reference types)。这最终会导致您的代码出现分段错误(一般来说,我建议您在使用动态转换的对象之前总是添加一个 if (d_1 != nullptr)
)。
更新:
顺便说一句,这实际上是dynamic_cast
必要性的一个很好的例子。即使您可能想在您的示例中使用 static_cast
并且它会编译,您将处理 未定义的行为 。使用 static_cast
将编译而不会出现问题,但您实际上会使用损坏的类型。假设 derived_1::printing()
访问一些变量 derived_1::a
,它在 derived_2
中不存在。通过将 derived_2
对象(没有 a
)静态侧投到 derived_1
对象 d_1
,您会错误地假设 d_1
包含一些有效a
,事实并非如此
示例:
// ...
struct derived_1 :public base
{
const int a = 123;
void printing() override {cout<<"derived_1 printing " << endl;}
void foo() { cout << "Foo using constant = " << a << endl; }
};
// ...
int main()
{
base * b = new derived_2();
derived_1 *d_1 = static_cast<derived_1*>(b);
d_1->printing(); // Will call derived_2::printing(), which is not what you expect!
d_1->foo(); // Won't show a = 123 but some nonesense (mostly 0),
// because a is not defined in derived_2.
}