第一次遇到这个名词(Object slice)在meyers的Effective STL中。有一条忠告:
不要尝试使用STL容器,管理多态的类对象。类似:
class Base{
public:
virtual void fun(){cout << "Base" << endl;}
};
class Derived1 : public Base {
public:
virtual void fun(){cout << "Derived1" << endl;}
};
class Derived2 : public Base {
public:
virtual void fun(){cout << "Derived2" << endl;}
};
void main()
{
vector<Base> vb;
Derived1 d1;
Derived2 d2;
vb.push_back(d1);
vb.push_back(d2);
vb[0].fun();
vb[1].fun();
}
以上两次调用fun(),输出结果均为”Base”。原因就是在vb.push_back时发生了“object slice“。
换句话说,如果向基类对象建立一个容器中插入派生类对象,那么当对象放入容器的时候对象的派生部分不会被复制进容器。
注:可以看出STL管理对象的方式,无论是将对象放入容器,还是从容器中拿出对象(当然不包括operator[]),都是以复制的方式。即,如果insert或push_back(obj),放入容器的不是obj自己,而是obj的一个拷贝。
再说回Object slice,《Inside the C++ Object Model》中介绍是为什么会产生Object slice。简单的说就是,当你将一个派生类对象复制给基类对象时,为了保证内存空间的正确性,编译器只能将派生类对象切割,填充到基类对象的内存空间中(同时,虚表不会被重新赋值)。派生部分就是被切割的那部分。
相同道理,以下代码也会发生object slice:
void main()
{
Base bs;
Derived1 dv1;
bs = dv1; // dv1会被slice
bs.fun(); // 会输出 Base
}