Stroustrup线性化类层次结构的解释示例

xan*_*xan 5 c++ diamond-problem

在Stroustrup的C++编程语言(第4版)中,第27.4.2节展示了一种"线性化"菱形类层次结构的技术,以避免虚拟基类的开销.他从一个真实项目(数据代码分析器工具)的钻石图案开始:

在此输入图像描述

线性版本绘制为:

在此输入图像描述

在此输入图像描述

代码大纲是:

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> { ... };
    }
}
Run Code Online (Sandbox Code Playgroud)

我对不规则结构感到困惑.基于最初的描述,我期待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> { ... };    
}
Run Code Online (Sandbox Code Playgroud)

而且我在想这些类的完整图表是:

在此输入图像描述

我的问题是,为什么"内部"三个impl模板类没有并行形式,就像我的代码版本一样?

xan*_*xan 2

我最好的猜测来自于查看实际的 Pivot 代码,其中包含

template<class D> struct Decl : Stmt<Node<D>> { ... };
Run Code Online (Sandbox Code Playgroud)

而不是斯特鲁斯特鲁普的

template<class D> struct Decl : Stmt<Expr<D>> { ... };
Run Code Online (Sandbox Code Playgroud)

这表明毕竟impl::Stmt不一定源自impl::Expr,如原始菱形图所示(尽管它仍然源自接口ipr::Expr)。它不是从impl::ExprforDecl和派生的Var,但它适用于其他实现类,例如impl::For

struct For : Stmt<Expr<ipr::For> > { ... }
Run Code Online (Sandbox Code Playgroud)

我不知道为什么斯特鲁斯特鲁普没有解释这种不规则现象。也许他认为他通过更改为Stmt<Node>来删除它Stmt<Expr>,或者也许他根本没有更改它(也就是说,代码在他复制后发生了更改)并且他想保持原样而不解释每个细节。

希望有更好的答案能够解释它。