使用派生类的新放置
placement new with derived class
C++ 大师。需要您帮助这个小挠头的人:
#include <iostream>
struct B{
virtual ~B() = default;
virtual void talk() { std::cout << "Be-e-en"; }
};
struct D:B{
void talk() override { std::cout << "Duhn"; }
~D() { std::cout << "~D()n"; }
};
int main(){
B b{}; // vptr points to B
new (&b) D; // vptr now points to D
b.talk(); // "Be-e-e" (why? shouldn't the vptr be used?)
b = D{}; // "~D()" (why? shouldn't the copying be elided?)
b.talk(); // "Be-e-e"
B*b1{new D};
b1->talk(); // "Duh"
delete b1; // "~D()"
return 0;
}
代码非常简单:在堆栈上放置一个基本对象,将新的派生对象放入其中(是的,eeew,但请耐心等待(并调用虚拟方法,期望打印派生的输出。
实际输出
上面的代码生成以下输出:
贝伊 ~D(( 贝伊 铜 ~D((
这种行为在MSVC,gcc,clang和我尝试过的一些在线编译器上普遍观察到(这是一个非常强烈的迹象,表明是我错了(。
第 1 部分
放置新将派生类型对象重新新闻到基本类型内存中。这会更新 vptr 以指向派生类型的 vtable(直接在调试器中观察到(。
主要问题:这是预期的行为吗?(我想说"是",所以如果不是 - 请向我解释(
我想相信执行放置新(前提是派生类型对象有足够的内存(应该就地初始化派生类型的全新对象。
如果我的理解是正确的,第一个b.talk()
应该输出"Duh"
因为现在的对象是派生类型的。为什么还在打印"Be-e-e"
?
将派生类型对象分配给基类型对象(除了导致对象拼接(不会复制 vptr,因此需要第二个"Be-e-e"
输出,前提是当我们到达该行代码时对象仍然是基类型。
第 2 部分
为什么b = D{};
作业中有~D()
调用?难道它不是一个临时的,应该被复制省略,不需要对那个临时的析构函数调用吗?
第 3 部分
最后一个使用指针的代码块"按预期"工作,仅用于健全性检查
查看代码:
B b{}; // vptr points to B
new (&b) D; // vptr now points to D
这是一个潜在的问题,原因有两个。首先,您没有调用基对象的析构函数B
。其次,B
的大小可能太小,无法容纳D
类型的对象。
b.talk(); // "Be-e-e" (why? shouldn't the vptr be used?)
虚拟调用仅在通过指针或引用调用时才有效。像这样的直接函数调用从不使用虚拟调度。
b = D{}; // "~D()" (why? shouldn't the copying be elided?)
因为b
被声明为类型B
并且您不能在D
和B
等不同类型之间省略副本。
相关文章:
- 有没有比在库中添加一个并非由所有派生类实现的新虚拟函数更好的设计实践
- 是否可以为 QPixmap 派生类嵌入缩放方法?
- 放置派生C++的新基子对象
- 使用派生类的新放置
- 如何在新的派生对象中获取基本对象的数据?
- 我可以将新的 std::tuple 放入内存映射区域,并在以后读回吗?
- 如何删除派生类中基类对象的新对象
- 根据参数创建派生类的新实例
- 如何创建指向派生类的新指针,该派生类在C++编译时未知
- 没有新成员的模板多态性派生类的大小
- 在C 中,是为派生类创建的一组新的私人变量
- 没有新字段 c++ 的派生类的非虚拟销毁
- C++,打开和编辑文本文件中的数字数据,并将结果放入新文件中
- 将 int 放入 char 数组是否在法律上需要新的放置
- 如何在Qt中派生新的基本文件名
- 派生类的新构造函数未生成:"overloaded member function not found"
- C++:新的基类,但它可以访问派生类的属性
- 重新编译二进制类或派生类,以便在基类中添加新方法
- 如何在MPI中从结构类型创建新的派生数据类型
- 自动注册新的派生类/创建者方法