Was sind die typischen Problemmuster, die von einem Code profitieren, der so konzipiert ist, dass er vielfache Vererbung nutzt?
Dies ist nur ein Beispiel, das für mich von unschätzbarem Wert ist, um die Sicherheit zu verbessern und die Versuchung zu lindern, kaskadierende Änderungen für Anrufer oder Unterklassen anzuwenden.
Wo ich mehrfache Vererbung für unglaublich nützlich befunden habe, selbst für die abstraktesten, zustandslosen Schnittstellen, ist die nicht-virtuelle Schnittstellen-IDiom (NVI) in C ++.
Sie sind nicht einmal wirklich abstrakte Basisklassen so viel wie Schnittstellen , die nur noch ein wenig Implementierung ihnen die universellen Aspekte ihrer Verträge zu erzwingen, da sie nicht wirklich die Allgemeingültigkeit des Vertrages so viel wie besser verengenden Strafvollzug .
Einfaches Beispiel (einige könnten überprüfen, ob ein übergebenes Dateihandle offen ist oder so ähnlich):
// Non-virtual interface (public methods are nonvirtual/final).
// Since these are modeling the concept of "interface", not ABC,
// multiple will often be inherited ("implemented") by a subclass.
class SomeInterface
{
public:
// Pre: x should always be greater than or equal to zero.
void f(int x) /*final*/
{
// Make sure x is actually greater than or equal to zero
// to meet the necessary pre-conditions of this function.
assert(x >= 0);
// Call the overridden function in the subtype.
f_impl(x);
}
protected:
// Overridden by a boatload of subtypes which implement
// this non-virtual interface.
virtual void f_impl(int x) = 0;
};
In diesem Fall wird es möglicherweise f
von tausend Stellen in der Codebasis aufgerufen, während f_impl
es von hundert Unterklassen überschrieben wird.
Es wäre schwierig, diese Art von Sicherheitsprüfung an allen 1000 Orten durchzuführen, die anrufen, f
oder an allen 100 Orten, die außer Kraft gesetzt werden f_impl
.
Indem ich nur diesen Einstiegspunkt für die Funktionalität nicht-virtuell mache, habe ich einen zentralen Ort, an dem ich diese Prüfung durchführen kann. Und diese Prüfung reduziert die Abstraktion nicht im Geringsten, da sie lediglich eine Voraussetzung für den Aufruf dieser Funktion darstellt. In gewisser Weise stärkt dies den Vertrag, der von der Schnittstelle bereitgestellt wird, und verringert die Belastung durch die Überprüfung der x
Eingabe, um sicherzustellen, dass sie an allen 100 Stellen, an denen sie außer Kraft gesetzt wird, den gültigen Voraussetzungen entspricht.
Ich wünschte, jede Sprache hätte und wünschte sich auch in C ++, dass es sich eher um ein natives Konzept handelt (z. B .: Wir müssten keine separate Funktion zum Überschreiben definieren).
Dies ist äußerst nützlich, wenn Sie dies nicht assert
im Voraus getan haben und festgestellt haben, dass Sie es später benötigen, wenn an zufälligen Stellen in der Codebasis negative Werte übergeben werden f
.