对象切片(slice)可能影响派生类对象
时间:2010-10-07 来源:slimzhao
class B {};
class D: public B {};
void foo(B b);
int main() { D d; foo(d); return 0; }
这种情况下, D在装B, 发生对象切片, "切"字用在这里有一个不当的误导, 就是D中B的部分, 被切走之后就不存在了, 实际上, 逻辑上D中那个隐含的B部分, 应该保持不变, 但是, 编译器实现这种对象切片的方式, 却有可能破坏D中的那个B的状态. 需要这种切片时, 编译器会将D视为一个B对象, 然后由一个B对象构造另一个在栈上的B对象, 供函数foo使用, 这里会调用copy ctor函数, 如果B和D这样定义:
class B { private: int i_; public: B(): i_(1) {} B(B & other) { this->i_ = other.i_;
other.i_ = 0; printf("addr: %p\n", &other); } void print() { printf("i = %d, %s\n", i_, __FUNCTION__ ); } };
class D: public B { private: int d_; };
void foo(B b) { b.print(); }
int main() { D d; printf("addr: %p\n", &d); d.print(); foo(d); d.print(); return 0; }
则B(B &other)的实现会改变到原始的D对象. 最后一个d.print将显示值0.
标准的copy ctor应该是 B (const B &other)这种形式, 但编译器也同样视B( B &other)为合法的形式, 考虑auto_ptr这种特殊类的实现, 需要转移指针的控制权时, 就需要这种用法.
看来, 切片是有潜在危险的, 应该尽量避免.
void foo(B b);
int main() { D d; foo(d); return 0; }
这种情况下, D在装B, 发生对象切片, "切"字用在这里有一个不当的误导, 就是D中B的部分, 被切走之后就不存在了, 实际上, 逻辑上D中那个隐含的B部分, 应该保持不变, 但是, 编译器实现这种对象切片的方式, 却有可能破坏D中的那个B的状态. 需要这种切片时, 编译器会将D视为一个B对象, 然后由一个B对象构造另一个在栈上的B对象, 供函数foo使用, 这里会调用copy ctor函数, 如果B和D这样定义:
class B { private: int i_; public: B(): i_(1) {} B(B & other) { this->i_ = other.i_;
other.i_ = 0; printf("addr: %p\n", &other); } void print() { printf("i = %d, %s\n", i_, __FUNCTION__ ); } };
class D: public B { private: int d_; };
void foo(B b) { b.print(); }
int main() { D d; printf("addr: %p\n", &d); d.print(); foo(d); d.print(); return 0; }
则B(B &other)的实现会改变到原始的D对象. 最后一个d.print将显示值0.
标准的copy ctor应该是 B (const B &other)这种形式, 但编译器也同样视B( B &other)为合法的形式, 考虑auto_ptr这种特殊类的实现, 需要转移指针的控制权时, 就需要这种用法.
看来, 切片是有潜在危险的, 应该尽量避免.
相关阅读 更多 +