Reputation: 2299
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.
Upvotes: 0
Views: 2145
Reputation: 73376
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).
Upvotes: 5
Reputation: 173
I would say with UML it's usually the type of relationship it has for example one to one or one to many. If you are deriving from an abstract class, interface or just another base class. Usually during inheritance you would use the protected keyword so that everything is private to any class outside of inheritance. After inheriting from a base class you can also override methods from the base class as well as run the base method from inside the overridden method.
I believe what you are looking for here is the protected keyword which basically is private inheritance. Only related classes have the ability to access such members. For example, you create a base class with protected members and then use these members in inherited classes or classes that derive from the base. Here is more info https://www.tutorialspoint.com/cplusplus/cpp_inheritance.htm
Upvotes: 0