[英]what does compiler do when new an object and assign the address of the created object to its base class pointer
[英]What did compiler do in this piece of code(Base class pointer to derived class object)?
在这段代码中:
#include<iostream>
using namespace std;
class B
{
int b;
public:
~B(){ cout <<"B::~B()"<<endl; }//1
};
class D: public B
{
int i,d,e,f;
public:
~D() { cout <<"D::~D()"<<endl; }//2
};
int main(void)
{
cout << "sizeB:" << sizeof(B) << " sizeD:"<< sizeof(D) <<endl;
B *pb = new D[2];
delete [] pb;
return 0;
}
一开始,我不知道delete []如何正常工作。 然后我注意到了这一点:
B* pb = new D[2];
&pb[1] - &pb[0] == sizeof(B);
D* pd = new D[2];
&pb[1] - &pb[0] == sizeof(D);
编译器做了什么? 以及为什么它如此工作?
这里有UB,因为您要delete
类型B
数组,该数组具有动态类型D
n3376 5.3.4 / 3:
在第二种选择(删除数组)中, 如果要删除的对象的动态类型不同于其静态类型,则行为未定义
另外,由于要进行多态工作-您应将基类d-tor
设为virtual
。
根本不清楚您要问什么,但是执行此操作时:
B* pb = new D[2];
您正在动态分配D
对象的数组,并且使B*
指向第一个元素。 这里
D* pd = new D[2];
您还将分配一个D
对象数组,并使D*
指向第一个元素。
您在这些指针上执行的所有指针运算将分别基于B
和D
的大小。 这不是您想要的,因为B
和D
的大小不必相同。
需要明确的是:您没有“指向派生类对象的基类指针” ,而有一个指向派生类对象数组的基类指针。
在我看来,您真正想要的是一个指向 B
的指针数组,然后可以将其指向B
或D
对象,即多态数组。
还要注意,正如已经指出的那样,您需要将B
的析构函数声明为虚拟的。
首先,当您尝试通过B
指针删除D
对象时,您将需要B
的析构函数是virtual
,以避免未定义的行为(UB)。
但是即使在这种情况下,您也将成为从C继承的C ++不幸功能的受害者。也就是说:数组似乎可以多态工作,但它们却无法工作。
STL容器可防止您遇到此陷阱。 例如:
std::vector<B> = std::vector<D>(2); // Illegal
但这不是数组的情况。 您的示例进行了编译,但是随后发生了奇怪的事情,因为您确实有一个D
数组,但通过B*
使用它。 指针算术失败,因为运行时认为它具有B
而不是D
的数组,而delete[]
再次失败,因为运行时认为它必须删除B
的数组而不是D
哦,你可以尝试插入B
您的阵列中的D
,当你使用它通过B*
; 这样可以编译,但是在运行时再次失败。
总结:不要因为您在代码中看到的原因而尝试多态使用容器。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.