从标准库容器继承会导致切片
Posted
技术标签:
【中文标题】从标准库容器继承会导致切片【英文标题】:Inheriting from standard library containers results in slicing 【发布时间】:2020-10-09 12:22:39 【问题描述】:我遇到了一个旧的SO post about inheriting from std::vector。我不清楚其中一个 cmets,为什么当您从标准库容器继承并使用指向基的指针/引用时会发生切片?
Godbolt
#include <vector>
#include <iostream>
using namespace std;
class MyVec : public vector<int>
;
void printTypeBase(vector<int>& vecObj)
cout << "base parameter ref: " << typeid(vecObj).name() << endl;
void printTypeDerived(MyVec& vecObj)
cout << "derived parameter ref: " << typeid(vecObj).name() << endl;
int main()
auto myVec = MyVec;
printTypeBase(myVec);
printTypeDerived(myVec);
输出:
基本参数参考:St6vectorIiSaIiEE
派生参数参考:5MyVec
当我尝试在 printTypeBase
内进行动态转换时:
auto temp = dynamic_cast<MyVec&>(vecObj);
我收到一条明确的错误消息:
错误:'std::vector
' 不是多态的
回想起来,我的问题应该是为什么std::vector
不是多态类型?
【问题讨论】:
这里没有进行切片,因为使用了指向引用的指针。在任何地方用class foo
替换std::vector<int>
,你会得到相同的结果。
C++ 中的类型不是动态的,它们是固定的和静态的。在printTypeBase
函数中,vecObj
变量是对vector<int>
的引用,编译器无法更改它。
这不是切片。 MyVec
是一个空的派生类。里面没有什么可以切的。如果要查看切片,则添加一个数据成员,例如 int
,然后通过 vector<int>&
复制对象。然后你得到int
成员的切片,因为vector<int>::operator=
对int
成员一无所知。
@SamVarshavchik when I replace vector<int> with a foo class 其中包含虚函数,我得到“正确”行为,typeid 为这两个函数打印“MyVec”。我现在明白了关于非多态类型的意义,所以这是有道理的。
即使使用虚函数,仍然不会发生切片。它仅在基类被复制 时发生。不进行复制。 typeid
并不表示对象切片正在发生。
【参考方案1】:
标准库容器没有虚拟方法,也没有虚拟析构函数。他们完全没有 vtable。
您的代码无法测试您想要测试的内容。
【讨论】:
【参考方案2】:但是,对于非多态类型的引用(例如没有虚拟方法的类),这里不会发生切片,typeid
解析为参数的静态类型信息,而不是动态类型。
【讨论】:
【参考方案3】:为什么会出现切片
您的示例中没有切片。与从任何其他类型继承相比,标准库容器没有什么特别会导致切片。
基本参数参考:St6vectorIiSaIiEE
错误:'std::vector
' 不是多态的
后一个错误解释了typeid
的结果。 Vector 不是多态类型。这是因为它没有虚函数。 dynamic_cast
只允许用于多态类型,typeid
仅在引用多态类型时才解析为动态类型。
【讨论】:
以上是关于从标准库容器继承会导致切片的主要内容,如果未能解决你的问题,请参考以下文章