Полезна ли нарезка объектов?

Разрезание объектов происходит, когда мы присваиваем или копируем объект производного класса объекту его базового класса, теряя его производную часть в процессе.

Это было объяснено более подробно здесь: В чем проблема нарезки в C ++?.

(Сам я не вижу в этом проблема, скорее естественное следствие семантики значения языка, но не в этом вопрос.)

Что мне интересно, так это: были ли ситуации, когда вы использовали бы это намеренно? Ситуация, где это «правильный инструмент для работы»?

14

Решение

Конечно, это может быть полезно, когда вы хотите удалить производную часть класса, возможно, чтобы удалить зависимости.

Например, скажем, у нас есть настройка объектной системы, в которой каждая база принадлежит производному типу, а каждый производный тип имеет различные зависимости, возможно, выполняемые путем внедрения зависимостей. Может потребоваться создать клон базы, хотя может потребоваться назначить совершенно новый набор зависимостей для фактического производного типа этой базы.

Это можно сравнить с игровым движком, где есть много типов коллайдеров. Каждый коллайдер происходит от базового интерфейсного объекта различными способами. Мы хотим клонировать коллайдер, чтобы получить его положение и масштаб (из базы), но хотим поместить совершенно другую производную реализацию поверх этой базы. «Нарезка объектов» может быть простым способом для достижения этой цели.

На самом деле, организация компонента или совокупного объекта будет иметь гораздо больший смысл, чем разделение объектов, но это в основном та же идея.

6

Другие решения

Некоторые реализации 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);
}
1

По вопросам рекламы [email protected]