我对dynamic_cast如何将数组的元素强制转换为更大的类感到好奇(它会将所有其他元素都移位了吗?)。所以我写了一个小代码尝试一下。但是我很惊讶,因为它在第一行只是编译而出现段错误。为什么 ?
#include <iostream>
class A
{
public:
virtual ~A() {}
};
class B : public A
{
public:
int x;
};
class C : public A
{
public:
int x;
int y;
};
int main()
{
A* aArray = new B[2];
(dynamic_cast<B&>(aArray[0])).x = 1; //segfault here
(dynamic_cast<B&>(aArray[1])).x = 2;
(dynamic_cast<C&>(aArray[0])).y = 3;
std::cout << (dynamic_cast<B&>(aArray[1])).x << std::endl;
return 0;
}
我来啦。我编译并使用gdb运行
首先,我设置打印对象选项:
(gdb) set print object
检查aArray的地址
(gdb) print aArray
$1 = (B *) 0x8003a404
检查A和B的大小
(gdb) print sizeof(B)
$2 = 8
(gdb) print sizeof(A)
$3 = 4
获取aArray的地址[0]
(gdb) print &aArray[0]
$4 = (B *) 0x8003a404
获取aArray的地址[1]
(gdb) print &aArray[1]
$5 = (A *) 0x8003a408
如果查看表达式
p[1]
,p
它是Base*
(Base是完全定义的类型),1是int,因此根据ISO / IEC 14882:2003 5.2.1 [expr.sub],此表达式有效且与*((p)+(1))
和
从5.7 [expr.add] / 5开始,将整数添加到指针时,只有当指针指向数组对象的元素并且指针算术的结果也指向该元素时,才可以很好地定义结果数组对象或数组末尾的一个。但是,p不指向数组对象的元素,而是指向派生对象的基类子对象。是派生对象是数组成员,而不是基础子对象。
在这种特定情况下,指针算法的实现是通过指针类型的大小来增加指针内存(但请参考此答案以获取更多细微差别)。
的作用aArray + 1
是指向类型A的对象数组的第二个元素
符合:
(gdb) print (A*)(((char *)aArray) + sizeof(A))
$6 = (A *) 0x8003a408
...但是aArray
实际上是B型对象的数组。
因此,数组的第二个元素是:
(gdb) print &((B *)aArray)[1]
$6 = (B *) 0x8003a40c
因此您最终指向第一个B对象的中间某处...而该访问导致了分段错误。
有关替代说明的示例,请参见:[ http://www.parashift.com/c++-faq/array-derived-vs-base.html]
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句