Объяснение примера линеаризации иерархий классов Строструпа


В языке программирования Строструпа C++ (4-е изд.), раздел 27.4.2 показывает метод "линеаризации" иерархии классов diamond, чтобы избежать накладных расходов виртуальных базовых классов. Он начинает с алмазного узора из реального проекта (Pivot Code analyzer tool):

Введите описание изображения здесь

Линейный вариант рисуется следующим образом:

Введите описание изображения здесь

И

Введите описание изображения здесь

Схема кода такова:

namespace ipr {
    struct Node { ... };
    struct Expr : Node { ... };
    struct Stmt : Expr { ... };
    struct Decl : Stmt { ... };
    struct Var : Decl { ... };

    namespace impl {
        template<class T> struct Node : T { ... };
        template<class T> struct Expr : Node<T> { ... };
        template<class S> struct Stmt : S { ... };
        template<class D> struct Decl : Stmt<Expr<D>> { ... };
        struct Var : Decl<ipr::Var> { ... };
    }
}

Меня смущает нерегулярная структура. На основе начальное описание, я ожидал, что impl будет выглядеть примерно так:

namespace impl {
    template<class T> struct Node : T { ... };
    template<class T> struct Expr : Node<T> { ... };
    template<class S> struct Stmt : Expr<S> { ... };
    template<class D> struct Decl : Stmt<D> { ... };
    struct Var : Decl<ipr::Var> { ... };    
}

И я думаю, что полная диаграмма этих классов:

Введите описание изображения здесь

Мой вопрос: , почему "внутренние" три класса шаблонов impl не имеют параллельных форм, как в моей версии кода?

1 5

1 ответ:

Мое лучшее предположение исходит из того, что я смотрю на фактический сводный код , который имеет

template<class D> struct Decl : Stmt<Node<D>> { ... };

Вместо Строструпа

template<class D> struct Decl : Stmt<Expr<D>> { ... };
Это предполагает, что impl::Stmt не обязательно выводится из impl::Expr, как в исходной диаграмме алмаза (хотя она все еще выводится из интерфейса ipr::Expr). Он не является производным от impl::Expr для Decl и Var, но он делает это для других классов реализации, таких как impl::For:
struct For : Stmt<Expr<ipr::For> > { ... }

Я не уверен, почему Страуструп не объяснить неровность. Возможно, он думал, что удалил его, изменив Stmt<Node> на Stmt<Expr>, или, возможно, он вообще не изменял его (то есть код изменился после того, как он скопировал его), и он хотел оставить его как есть, не объясняя каждую деталь.

Надеюсь, что лучший ответ объяснит это.