Лучший способ борьбы с этой проблемой, как правило, состоит в том, чтобы следовать рекомендации Скотта Мейера (см. Эффективный C ++ ) о наличии только конкретных классов в конечных узлах вашего дерева наследования и обеспечении абстрактности неконечных классов имея хотя бы одну чисто виртуальную функцию (деструктор, если не что иное).
Удивительно, как часто этот подход помогает прояснить дизайн и другими способами. В любом случае усилия по выделению общего абстрактного интерфейса, как правило, являются полезными при проектировании.
Редактировать
Хотя я изначально не делал этого ясным, мой ответ исходит из того факта, что невозможно точно предупредить о нарезке объектов во время компиляции, и по этой причине это может привести к ложному чувству безопасности, если у вас есть утверждение времени компиляции или предупреждение компилятора включено. Если вам нужно узнать о случаях нарезки объектов и исправить их, это означает, что у вас есть желание и возможность изменить унаследованный код. Если это так, то я считаю, что вам следует серьезно подумать о рефакторинге иерархии классов как о способе сделать код более надежным.
Мои рассуждения таковы.
Рассмотрим некоторый библиотечный код, который определяет класс Concrete1 и использует его в качестве интерфейса к этой функции.
void do_something( const Concrete1& c );
Передача type be reference для эффективности и, в общем, хорошая идея. Если библиотека считает Concrete1 типом значения, реализация может принять решение сделать копию входного параметра.
void do_something( const Concrete1& c )
{
// ...
some_storage.push_back( c );
// ...
}
Если тип объекта передаваемой ссылки действительно Concrete1
, а не какой-либо другой производный тип, тогда этот код подходит, разделение не выполняется. Общее предупреждение об этом push_back
вызове функции может привести только к ложным срабатываниям и, скорее всего, будет бесполезным.
Рассмотрим некоторый клиентский код, который получает Concrete2
из Concrete1
и передает его в другую функцию.
void do_something_else( const Concrete1& c );
Поскольку параметр берется по ссылке, здесь не происходит среза в параметре для проверки, поэтому было бы неправильно предупреждать здесь о срезах, поскольку может случиться так, что срезы не происходят. Передача производного типа в функцию, которая использует ссылку или указатель, является распространенным и полезным способом использования преимуществ полиморфных типов, поэтому предупреждение или запрещение этого может показаться контрпродуктивным.
Так где же ошибка? Что ж, «ошибка» заключается в передаче ссылки на что-то, производное от класса, который затем обрабатывается вызываемой функцией как тип значения.
В общем, нет способа сгенерировать постоянно полезное предупреждение о времени компиляции от среза объектов, и поэтому лучшая защита, где это возможно, - устранить проблему путем разработки.