In C++, one can create a sub-class via public
, protected
, or private
inheritance. What's the notation to indicate that in a UML class diagram? I'm thinking about putting a label on the arrow but not sure if that's common practice.
Private inheritance in C++, such as:
class B1 {
public:
void test();
...
};
class D1 : private B1 {
public:
void demo() { test(); }
...
};
means that every instance of D1
is an instance of B1
, but that is hidden for the outside world. This strange construct aims at implementing the derived class by reusing the code of the base class, but as if there would be no inheritance.
In consequence, unlike public inheritance, a D1 object could not be used where a B1 object is expected:
B1 *p = new D1; //ouch -> error: ‘B1’ is an inaccessible base of ‘D1’
In UML, when a derived class specializes a more general base classe, it means the following:
Type conformance means that if one Type conforms to another, then any instance of the first Type may be used as the value of a TypedElement whose type is declared to be the second Type. A Classifier is a Type, and conforms to itself and to all of its generalizations.
So in UML, if D1 specialises (i.e. inherits from) B1, a D1 instance could always be be used in place of a B1 object. This does not match the C++ private inheritance.
Moreover, there is not either a realization relationship between an interface and its implementations either, since D1 does not conform to the interface defined by B1:
An InterfaceRealization relationship between a BehavioredClassifier and an Interface implies that the BehavioredClassifier conforms to the contract specified by the Interface by supporting the set of Features owned by the Interface, and any of its parent Interfaces.
Obviously, there is a dependency: D1 depends on B1. So you could simply show a dependency. But this does not really help to grasp the kind of relationship and is not very useful. (unless you add a comment to explain)
A better approach would therefore be to map UML to match the C++ semantics. In this regard, you could envisage to model the private inheritance as a composition relation:
Why? Because the situation is very similar (although not completely) to the following composition alternative:
class B2 {
public:
void test();
...
};
class D2 {
private:
B2 base; // instead of private inheritance
public:
void demo() { base.test(); } // base members accessed via base
...
};
So all we do in the UML model here, is to make explicit that in any D1 instance, there is a B1 sub-object not accessible directly from the outside world.
In the former and now obsolete UML 1.4, a generalization relationship could have a stereotype «Implementation»
that would have fulfilled your need, but is no longer supported since 2005, and might mislead some readers who associate "implementation" with interface:
Specifies that the child inherits the implementation of the parent (its attributes, operations and methods) but does not make public the supplier's interface, nor guarantee to suport them, thereby violating substituability. This is private inheritance and is usually used only for programming implementation puproposes.
Digging a little bit in the UML metamodel, it appears that generalization has a isSubstitutable
property which is true by default. So you could think of using your own language-specific profile, and define therein a stereotypes «Private inheritance»
and «Protected inheritance»
for a specialization of the Generalization
metamodel element, both with isSubstituable=false
. This would allow:
This could be a very pragmatic and readable way to convey your language-specific design intent, including that a D1 object is not substituable for B1. But be aware that this is not without risks: isSubsituable
is only about run time promises, and has in reality no impact regarding inheritance rules of public features in UML. Automated tools might therefore come to a different conclusion than your readers (this is why I proposed another approach above).