对象切片是否有用?

时间:2013-05-07 09:55:45

标签: c++ inheritance object-slicing

当我们将派生类的对象分配或复制到其基类的对象时,会发生对象切片,在此过程中丢失它的派生部分。

这里有更深入的解释:What is the slicing problem in C++?

(我自己,我不认为它是问题,而是语言价值语义的自然结果,但这不是这个问题的重点。) < / p>

我想知道的是:有没有你有意使用它的情况?这是一个“工作的正确工具”吗?

2 个答案:

答案 0 :(得分:6)

当然,在想要删除类的派生部分时,它可能很有用,可能会删除依赖项。

例如,假设我们有一个对象系统设置,其中每个基类都属于派生类型,并且每个派生类型都有各种依赖关系,可能通过依赖注入来实现。可能希望创建基类的克隆,但可能希望为该基类的实际派生类型分配一组全新的依赖项。

这可以比作游戏引擎,其中有许多类型的碰撞器。每个碰撞器以各种方式从类似基础接口的对象派生。我们想要克隆一个碰撞器来检索它的位置和比例(从基础),但是想要在这个基础上放置一个完全不同的派生实现。 “对象切片”可能是实现这一目标的简单方法。

实际上,组件或聚合对象组织比具体的对象切片更有意义,但它大多是相同的想法。

答案 1 :(得分:1)

一些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,您可能希望使用对象成员函数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);
}