Search code examples
c++diamond-problem

Explanation of Stroustrup Linearizing Class Hierarchies example


In Stroustrup's C++ Programming Language (4th ed), section 27.4.2 shows a technique to "linearize" a diamond class hierarchy to avoid the overhead of virtual base classes. He starts with the diamond pattern from a real project (Pivot code analyzer tool):

enter image description here

The linear version is drawn as:

enter image description here

and

enter image description here

The code outline is:

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> { ... };
    }
}

I'm confused by the irregular structure. Based on the initial description, I was expecting impl to look something like:

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> { ... };    
}

And I'm thinking the full diagram of these classes is:

enter image description here

My question is, why don't the "interior" three impl template classes have parallel forms, as in my version of the code?


Solution

  • My best guess comes from looking at the actual Pivot code which has

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

    instead of Stroustrup's

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

    That suggests that impl::Stmt doesn't necessarily derive from impl::Expr after all, as in the original diamond diagram (though it still derives from the interface ipr::Expr). It doesn't derive from impl::Expr for Decl and Var, but it does for other implementation classes such as impl::For:

    struct For : Stmt<Expr<ipr::For> > { ... }
    

    I'm not sure why Stroustrup didn't explain the irregularity. Perhaps he thought he removed it by changing Stmt<Node> to Stmt<Expr>, or maybe he didn't change it at all (that is, the code changed after he copied it) and he wanted to leave it as is without explaining every detail.

    Hopefully a better answer will explain it.