目录
1.对象切割的场景
C++中,一个子类对象可以直接赋值给一个基类对象,但是反之则不行。
如下例子所示:
class Base {
int x, y;
};
class Derived : public Base {
int z, w;
};
int main()
{
Derived d;
Base b = d;// 会发生对象切割,d中的z和w成员会丢失。
}
对象切割发生在一个子类对象赋值给基类对象时,子类自有的数据成员会在基类的对象中被切割掉。
#include <iostream>
using namespace std;
class Base {
protected:
int i;
public:
Base(int a) { i = a; }
virtual void display() {
cout << "Base class object, i=" << i << endl;
}
};
class Derived : public Base {
int j;
public:
Derived(int a, int b) : Base(a) { j = b; }
virtual void display() {
cout << "Derived class object, i="<< i << ", j=" << j << endl;
}
};
// 全局函数.按值传递参数.
void somefunc(Base obj) {
obj.display();
}
int main() {
Base b(33);
Derived d(45, 54);
somefunc(b);
somefunc(d); // 发生对象切割,对象d中的成员j被丢失
return 0;
}
输出:
Base class object, i=33
Base class object, i=45
2.对象切割的避免方法
2.1使用引用
可以使用指针或者引用来避免这个问题。当使用指针或者引用来传递函数参数时,则不会发生对象切割。因为对于任何类型来说,指针都是占用相同内存大小的。
例如,如果把上面程序中的全局函数somefunc() 修改为下面代码,则不会产生对象切割问题。
void somefunc(Base &obj)
{
obj.display();
}
输出:
Base class object, i=33
Derived class object, i=45, j=54
2.2使用指针
同样,如果使用指针,也能得到同样的结果
void somefunc(Base *objp)
{
objp->display();
}
int main()
{
Base *bp =new Base(33) ;
Derived *dp =new Derived(45, 54);
somefunc(bp);
somefunc(dp); // 不会产生对象切割问题
return 0;
}
输出:
Base class object, i=33
Derived class object, i=45, j=54
2.3使用纯虚函数
也可以将基类成员函数定义为纯虚函数,来避免对象切割问题。因为虚基类是不能生成对象的。