我在使用自动存储持续时间声明的对象使用虚函数时遇到问题。这是一个可重现的场景:
>>> set(a) & set(b)
{'shampoo', 'product'}
>>> set(b) - set(a)
{'random', 'nothing'}
这打印“A”,而我希望它打印B.我很好奇为什么。
提前谢谢!
答案 0 :(得分:8)
你在这里slicing:
void setItem(A item) {
this->item = item;
}
当您将B
传递到item
时,setItem()
部分会被切掉,因此您将失去其中的基础部分。如果A
是抽象的,那么这将是一个更明显的错误(因为你不能按值存储抽象类)。
相反,您希望将项目存储为指针。
答案 1 :(得分:4)
这种现象称为对象切片。
基本上,当您将item
(B
类型)传递给setItem
(需要A
)时,您将失去每个 B
的信息,因为B
无法存储A
。
因此,当您致电printClassName
时,它只会从A
了解该功能,因此会从A
调用该功能。
一种可能的解决方案是将指针传递给对象,而不是原始数据。这将在您的示例中调用printClassName
B
,因为不会发生切片。
答案 2 :(得分:3)
为了说清楚,为了避免在这种情况下切换对象,您应该将void setItem(A item)
更改为void setItem(A& item)
和A getItem()
A& getItem()
。
这个(通过引用传递/返回)保留了动态类型,几乎可以肯定你在这种情况下的意图
编辑:我忽略了您存储的对象也是A
类型的事实。这不行。你需要将它作为一个指针,以便它能够与静态类型(或引用,但它必须在构造函数中初始化)具有不同的动态类型。
因此,要更改为使用指针,您可以尝试将A item
中的Test
更改为A* item
。然后设置/ get成为:
void setItem(A& item) {
this->item = &item;
}
A& getItem() {
return *(this->item);
}
这为您提供所需的输出。如果您只是测试多态行为,这是可以的,但是对于实际设计需要非常小心(例如,您可能想要考虑是否应该使用std::shared_ptr
来共享所有权。)