当我们将派生类的对象分配或复制到其基类的对象时,就会发生对象切片,在此过程中会丢失它的派生部分。
此处已对其进行了更深入的解释:C++ 中的切片问题是什么?.
(我自己,我不认为这是一个问题,而是语言价值语义的自然结果,但这不是这个问题的重点。)
我想知道的是:是否有过故意使用它的情况?它是“适合工作的工具”的情况?
当我们将派生类的对象分配或复制到其基类的对象时,就会发生对象切片,在此过程中会丢失它的派生部分。
此处已对其进行了更深入的解释:C++ 中的切片问题是什么?.
(我自己,我不认为这是一个问题,而是语言价值语义的自然结果,但这不是这个问题的重点。)
我想知道的是:是否有过故意使用它的情况?它是“适合工作的工具”的情况?
当然,当想要删除类的派生部分时,它可能很有用,也许是为了删除依赖项。
例如,假设我们有一个对象系统设置,其中每个基类都属于一个派生类型,并且每个派生类型都有各种依赖关系,可能通过依赖注入来实现。尽管可能需要为该基的实际派生类型分配一组全新的依赖项,但可能需要创建基的克隆。
这可以比作一个游戏引擎,其中有多种类型的碰撞器。每个对撞机都以各种方式派生自一个类似基本接口的对象。我们想要克隆一个对撞机来检索它的位置和比例(从基础),但是想要在这个基础上放置一个完全不同的派生实现。“对象切片”可能是实现这一目标的一种简单方法。
实际上,组件或聚合对象组织比专门的对象切片更有意义,但它基本上是相同的想法。
一些 STL 实现实际上使用对象切片来实现算法:例如,使用iterator_tags
您可以轻松地std::advance
使用最有效的算法:
namespace std {
template <class I>
void advance_impl(I& it, int n, input_iterator_tag) {
for (; n > 0; --n)
++it;
}
// Forward Iterators use the same implementation as Input Iterators...
// TODO:
// Add bidirectional_iterator_tag implementation...
template <class I>
void advance_impl(I& it, int n, random_access_iterator_tag) {
it += n;
}
template <class I>
void advance(I& it, int n) {
advance_impl(it, n, typename iterator_traits<I>::iterator_category());
}
} // std
使用您自己的小类层次结构,您可以消除模棱两可的函数重载。例如,将对象转换为std::string
您可能想要使用 objects 成员函数(to_string()
如果它存在)或以其他方式使用operator<<
.
struct R2 {}; // rank 2
struct R1 : R2 {}; // rank 1
// C++11.
// Use some type traits and enable_if in C++03.
template <class T>
auto ToString(R1, T const& t) -> decltype(t.to_string()) {
return t.to_string();
}
template <class T>
std::string ToString(R2, T const& t) {
std::ostringstream s;
s << t;
return s.str();
}
template <class T>
std::string ToString(T const& t) {
return ToString(R1(), t);
}