关于对象切片Thinking in C++中有这么一段话
英文原版:
If you upcast to an object instead of a pointer or reference,
something will happen that may surprise you: the object is “sliced”
until all that remains is the subobject that corresponds to the
destination type of your cast.
对于绿色这一段话,有些书译为:这个对象被”切片”,直到剩下的是适合于目的的子对象。//有点晦涩。。。
我的理解是:这个对象将被”分割”成只剩下与目的类型(即:转换以后的类型)相匹配的子对象(即:成员变量和函数)
这句话的意思也就是说:在函数传参处理多态性时,如果一个派生类对象在UpCasting时,用的是传值的方式,而不是指针和引用,那么,这个派生类对象在UpCasting以后,将会被slice(切分)成基类对象,也就是说,派生类中独有的成员变量和方法都被slice掉了,值剩下和基类相同的成员变量和属性。这个派生类对象被切成了一个基类对象。
那么我们来看个实例,真正理解什么是对象切片,代码如下:摘自Thiking In C++
在Slice前后,Dog类对象d的变化如下图:
注意到after Slice以后,虚函数表指针时Pet vptr,Dog类的favoriteActivity成员变量也不存在了。
其实这时候执行了一些步骤:
在正常情况下,main函数中执行describe函数,在传递Dog对象d的时候,调用了Pet类的拷贝构造函数,相当于此时,在describe函数中的那个Pet类对象p是拷贝构造的结果,所以,跟Dog对象d已经没有了关系。所以,此时,p.description()执行的会是调用的基类也就是Pet类的description函数。而也许,这并不是你所想要看见的结果(因为,你或许是想实现多态调用)
但是,此例中,恰恰因为Pet类中的description函数被声明为纯虚函数,它是不能被创建实例的,所以,在全局的describe函数中不可能有者拷贝构造函数来实例化一个Pet类对象。所以,此时,编译器就会报错。
而这种情况,也是纯虚函数存在的一个重要意义:避免对象切片。
纯虚函数的一个重要意义,就在于可以在编译期间避免对象切片,从而避免很多可能会出现的问题。