截切问题发生在企图把一个派生类对象复制到一个基类对象。
那些派生类专属的数据和行为会被切除,这是一种错误。
class Employee {
public:
virtual ~Employee();
virtaul void pay() const;
//…
protected:
void setType(int type) {
myType_ = type;
}
private:
int myType_;
};
class Salaried : public Employee {
//…
};
Employee employee;
Salaried salaried;
employee = salaried;//发生了截切
从salaried到employee的赋值操作时合法的,因为Salaried class对象is-a Employee class 对象,
但是结果可能非我们想要的。
在实践中,被截切之class对象的状态与行为脱节,是难以察觉的,引发的破坏就更大。
截切问题的最常见来源是一个派生类的class对象被以传值(by value)传递给一个基类类型的形参。
void fire(Employee victim);//函数名“解雇”,形参“倒霉蛋”
//…
fire(sllaried);//被截切
此问题可以用传递引用或指针(by reference/by pointer)方式来避免。
void rightSize(Employee &asset);
//…
rightSize(salaried);//正确
截切问题也可能以其它形式出现,尽管不常见。比如说,把一个派生类的基类类型子对象复制到另一个派生类
的基类类型子对象。
Employee *getNextEmployee();
//获取一个Employee的动态对象
//…
Employee *ep = getNextEmployee();
*ep = salaried;//截切
如果发生了截切问题,意味着继承体系设计中存在不周。
最好是避免让具体类(concrete class)成为基类。
class Employee {
public:
virtual ~Employee();
virtual void pay() const = 0;
//…
};
void fire(Employee);//编译出错
void rightSize(Employee &);//正确
Employee *getNextEmployee();//没问题
Employee *ep = getNextEmployee();//正确
*ep = salaried;//编译错误
Employee e2(salaried);//编译错误
抽象类不能够被具现,所以大多数引发截切的问题都会在编译期截获。