Für das Verständnis von Vorlagen ist es von großem Vorteil, die Terminologie klar zu formulieren, da die Art und Weise, wie Sie über sie sprechen, die Art und Weise bestimmt, wie Sie über sie nachdenken.
Insbesondere Area
handelt es sich nicht um eine Vorlagenklasse, sondern um eine Klassenvorlage. Das heißt, es ist eine Vorlage, aus der Klassen generiert werden können. Area<int>
ist eine solche Klasse (es ist kein Objekt, aber natürlich können Sie ein Objekt aus dieser Klasse auf die gleiche Weise erstellen, wie Sie Objekte aus einer anderen Klasse erstellen können). Eine andere solche Klasse wäre Area<char>
. Beachten Sie, dass dies völlig unterschiedliche Klassen sind, die nichts gemeinsam haben, außer der Tatsache, dass sie aus derselben Klassenvorlage generiert wurden.
Da Area
es sich nicht um eine Klasse handelt, können Sie die Klasse nicht daraus ableiten Rectangle
. Sie können eine Klasse nur von einer anderen Klasse (oder mehreren von ihnen) ableiten. Da Area<int>
es sich um eine Klasse handelt, können Sie beispielsweise daraus ableiten Rectangle
:
class Rectangle:
public Area<int>
{
// ...
};
Da Area<int>
und Area<char>
verschiedene Klassen sind, können Sie sogar gleichzeitig von beiden ableiten (wenn Sie jedoch auf Mitglieder zugreifen, müssen Sie sich mit Mehrdeutigkeiten auseinandersetzen):
class Rectangle:
public Area<int>,
public Area<char>
{
// ...
};
Sie müssen jedoch angeben, von welcher Klasse Sie beim Definieren ableiten möchten Rectangle
. Dies gilt unabhängig davon, ob diese Klassen aus einer Vorlage generiert werden oder nicht. Zwei Objekte derselben Klasse können einfach keine unterschiedlichen Vererbungshierarchien haben.
Sie können auch Rectangle
eine Vorlage erstellen. Wenn du schreibst
template<typename T> class Rectangle:
public Area<T>
{
// ...
};
Sie haben eine Vorlage, Rectangle
von der Sie eine Klasse erhalten können, von Rectangle<int>
der abgeleitet wird Area<int>
, und eine andere Klasse, von Rectangle<char>
der abgeleitet wird Area<char>
.
Es kann sein, dass Sie einen einzelnen Typ haben möchten, Rectangle
damit Sie alle möglichen Rectangle
Funktionen an dieselbe Funktion übergeben können (die selbst den Bereichstyp nicht kennen muss). Da die Rectangle<T>
durch das Instanziieren der Vorlage generierten Klassen Rectangle
formal unabhängig voneinander sind, funktioniert dies nicht. Sie können hier jedoch die Mehrfachvererbung verwenden:
class Rectangle // not inheriting from any Area type
{
// Area independent interface
};
template<typename T> class SpecificRectangle:
public Rectangle,
public Area<T>
{
// Area dependent stuff
};
void foo(Rectangle&); // A function which works with generic rectangles
int main()
{
SpecificRectangle<int> intrect;
foo(intrect);
SpecificRectangle<char> charrect;
foo(charrect);
}
Wenn es wichtig ist, dass Ihr Generikum Rectangle
von einem Generikum abgeleitet ist Area
, können Sie den gleichen Trick auch mit folgenden Methoden Area
ausführen:
class Area
{
// generic Area interface
};
class Rectangle:
public virtual Area // virtual because of "diamond inheritance"
{
// generic rectangle interface
};
template<typename T> class SpecificArea:
public virtual Area
{
// specific implementation of Area for type T
};
template<typename T> class SpecificRectangle:
public Rectangle, // maybe this should be virtual as well, in case the hierarchy is extended later
public SpecificArea<T> // no virtual inheritance needed here
{
// specific implementation of Rectangle for type T
};