Проблема, с которой вы сталкиваетесь, двойственная:
- Вы не вставляете
B
с в наборе, вы вставляете A
с (это проблема срезов)
operator<
неправильно определено для A
Я пропущу проблему нарезки объектов, она хорошо документирована. Если бы вы использовали чисто виртуальные функции (вместо бессмысленных определений), ваш код не скомпилировался бы, предотвращая проблему.
Теперь математически, всякий раз, когда определяется operator<
, он должен определять:
Здесь ваше «фиктивное» определение operator<
не может быть антисимметричным отношением, и, таким образом, алгоритмы (такие как вставка множества), которые наивно ожидают, что это будет выполнено ... неожиданно обнаружат, что дают бессвязные результаты :
Два раза меня спрашивали: «Помолитесь, мистер Бэббидж, если вы введете в машину неправильные цифры, будут ли правильные ответы?» ... Я не могу правильно понять, какое замешательство может вызвать такой вопрос.
- Чарльз Бэббидж , Отрывки из жизни философа
Я также хотел бы отметить, что фиктивное определение operator==
не может быть отношением эквивалентности (а именно a == a
не выполняется), однако ==
не используется для множества, поэтому оно не является причиной проблемы .
Я настоятельно призываю вас избегать определения фиктивного поведения, подобного таковому. Это может привести только к ошибкам. Вместо этого вы должны сделать такие виртуальные методы чистыми (чтобы эти проблемы обнаруживались во время компиляции) или, по крайней мере, вызвать исключение.