Search code examples
c++templatesinheritanceumlclass-diagram

UML:Inheritance between template classes with parameter dependencies


Pardon my poor english. Just let me show you the situation what I'm trying to draw in UML class diagram.

template<typename TB1, typename TB2, typename TB3>
class Base { ... };

template<typename TD1, typename TD2>
class Derived : public Base<typename TD1, typename TD2, int> { .... };

I know how to draw UML class diagram when a class inherits generic class, as below(similar question was asked before). UML

But what should I do if base class's template paramter type is being set by derived class's template parameter type? Just add another arrow indicating binded type depends on derived class's template parameter?


Solution

  • In short

    You could show the relationship between the template Base and the template Derived either with a parameter binding (like in your picture, but between two template classes) or inheritance between template classes.

    But neither alternative is completely accurate regarding the C++ and the UML semantics at the same time. For this you would need to decompose the template inheritance into a binding and an inheritance.

    More explanations

    What does your C++ code mean?

    The C++ generalization between Derived and Base makes three things at once:

    • it binds parameters of the Base template class (i.e. substituting TD1 for TB1, TD2 for TB2 and int for TB3);
    • it keeps TD1 and TD2 substituable in the resulting bound class;
    • it creates a generalization between the classes obtained by binding the parameters.

    For the readers who are less familiar with C++, let's illustrate this by using aliases to clarify:

    template<typename TB1, typename TB2, typename TB3>
    class Base {  };
    
    template<typename TD1, typename TD2>
    class Derived : public Base<TD1, TD2, int> { };
    
    int main() {
      using MyDerived = Derived<string, Test>; // class corresponding to binding parameters
      using MyBase = Base<string, Test, int>;  // also binding parameters
      MyBase *p = new MyDerived();         // this assignment works because the bound 
                                           // MyBase generalization is a generalization 
                                           // from MyDerived
    }
    

    So this code means that there is a generic specialization of Base into Derived which is true, whatever the parameter bindings, and in particular for the bound MyBase and MyDerived.

    How to show it in UML?

    Option 1 - binding

    A first possibility is to simply use <<bind>> between template classes:

    UML specs, section 9.3.3.1: (...) the details of how the contents are merged into a bound element are left open. (...) A bound Classifier may have contents in addition to those resulting from its bindings.

    Derived would be a bound classifier obtained by binding parameters of Base and adding "own content", including redefinitions of base elements ("overrides"). This is not wrong, but would not appropriately reflect that there is an inheritance also between bound classes obtained from Derived and bound classes obtained directly from Base.

    Option 2 - inheritance

    Another approach could be inheritance between the templates:

    enter image description here

    It corresponds to the C++ semantics. But the UML section 9.9.3.2 Template classifier specializations gives another semantic to this diagram:

    A RedefinableTemplateSignature redefines the RedefinableTemplateSignatures of all parent Classifiers that are templates. All the formal TemplateParameters of the extended (redefined) signatures are included as formal TemplateParameters of the extending signature, along with any TemplateParameters locally specified for the extending signature.

    I understand this as meaning that the template parameters increase (i.e. the set would be TB1, TB2, TB3, TD1 and TD2) and there is no semantics nor notation foreseen to define a local binding of some parents elements. So UML readers might misunderstand the design intent.

    Option 3 - binding and inheritance

    The cleanest way would therefore be to decompose the binding and the inheritance (I've used a bound class that is itself templated with the new parameter name to align, but this could be overkill) :

    enter image description here