Прямого пути нет, но вы можете написать виртуальный size()
метод, который могут реализовать дочерние классы. Промежуточный класс шаблонов может автоматизировать работу ног.
struct base {
virtual size_t size() const =0;
virtual ~base() { }
};
template<typename T>
struct intermediate : base {
virtual size_t size() const { return sizeof(T); }
};
struct derived : intermediate<derived>
{ };
Это требует, чтобы ваша иерархия была полиморфной ... однако, запрос поведения, основанного на динамическом типе объекта, а не на его статическом типе, является частью определения полиморфного поведения. Так что это не добавит v-таблицу к среднему сценарию использования, поскольку, по крайней мере, у вас, вероятно, уже есть виртуальный деструктор.
Эта конкретная реализация действительно ограничивает ваше дерево наследования одним уровнем, не входя в множественное наследование [т.е. тип, производный от derived
, не получит свое собственное переопределение size
]. Есть немного более сложный вариант, который обходит это.
struct base { /*as before */ };
template<typename Derived, typename Base>
struct intermediate : Base {
virtual size_t size() const { return sizeof(Derived); }
};
struct derived : intermediate<derived, base>
{ };
struct further_derived : intermediate<further_derived, derived>
{ };
По сути, это вставляет intermediate
между каждым фактическим слоем вашей иерархии, каждый переопределяет size
с соответствующим поведением и происходит из базового типа фактический . Повторите до тошноты.
//what you want
base >> derived
>> more_deriveder
>> most_derivedest
//what you get
base >> intermediate<derived, base>
>> derived >> intermediate<more_deriveder, derived>
>> more_deriveder >> intermediate<most_derivedest, more_deriveder>
>> most_derivedest
Несколько библиотек типов миксинов используют такую схему, так что миксины могут быть добавлены в существующую иерархию без использования множественного наследования. Лично я редко использую более одного уровня наследования, поэтому я не беспокоюсь о дополнительной сложности, но ваш пробег может отличаться.