Erben von einer Vorlagenklasse in c ++

105

Angenommen, wir haben eine Vorlagenklasse Areamit einer Mitgliedsvariablen T area, einer T getArea()und einer void setArea(T)Mitgliedsfunktion.

Ich kann ein AreaObjekt eines bestimmten Typs durch Eingabe erstellen Area<int>.

Jetzt habe ich eine Klasse Rectangle, die die AreaKlasse erbt . Da es Rectanglesich nicht um eine Vorlage handelt, kann ich nicht tippen Rectangle<int>.

Wie spezialisiere ich den geerbten AreaTyp für RectangleObjekte?

EDIT: Entschuldigung, ich habe vergessen zu klären - meine Frage ist, ob es möglich ist, Area zu erben, ohne es zu spezialisieren, so dass es nicht als Area of ​​Ints geerbt wird, sondern als Area Rectangle die Typen für spezialisieren kann.

dtech
quelle
3
Es ist eine Klassenvorlage , da es eine Vorlage ist, aus der Klassen generiert werden.
sbi
1
@sbi Ich habe nicht vor, hier einen Flammenkrieg zu beginnen, aber wenn Bjarne Stroustrup nicht zwischen Klassenvorlage und Vorlagenklasse unterscheidet (siehe Die Programmiersprache C ++ , 4. Ausgabe, Abschnitt 23.2.1), sollten Sie dies nicht tun auch nicht.
Michael Warner
@ MichaelWarner Ich scheine mich zu erinnern, dass er die Unterscheidung getroffen hat. Das war jedoch in den 90ern im Usenet. Vielleicht hat er seitdem aufgegeben. (Oder vielleicht bezeichnet er eine instanziierte Klassenvorlage als Vorlagenklasse?)
sbi

Antworten:

244

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 Areahandelt 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 Areaes 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 Rectangleeine Vorlage erstellen. Wenn du schreibst

template<typename T> class Rectangle:
  public Area<T>
{
  // ...
};

Sie haben eine Vorlage, Rectanglevon 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, Rectangledamit Sie alle möglichen RectangleFunktionen an dieselbe Funktion übergeben können (die selbst den Bereichstyp nicht kennen muss). Da die Rectangle<T>durch das Instanziieren der Vorlage generierten Klassen Rectangleformal 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 Rectanglevon einem Generikum abgeleitet ist Area, können Sie den gleichen Trick auch mit folgenden Methoden Areaausfü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
};
Celtschk
quelle
Hinweis: Ein Vorlagentypparameter ist Teil der Klasse eines Objekts, das diese Klassenvorlage instanziiert. Mit anderen Worten, es ist keine Komponente der Klasse, sondern Teil des Typs.
Nikos
20

Versuchen Sie nur abzuleiten Area<int>? In welchem ​​Fall tun Sie dies:

class Rectangle : public Area<int>
{
    // ...
};

BEARBEITEN: Nach der Klarstellung scheint es, dass Sie tatsächlich auch versuchen, Rectangleeine Vorlage zu erstellen. In diesem Fall sollte Folgendes funktionieren:

template <typename T>
class Rectangle : public Area<T>
{
    // ...
};
Stuart Golodetz
quelle
8
class Rectangle : public Area<int> {
};
ldanko
quelle
8

Machen Sie Rectangle zu einer Vorlage und geben Sie den Typnamen an Area weiter:

template <typename T>
class Rectangle : public Area<T>
{

};
pezcode
quelle
6

Rectanglemuss eine Vorlage sein, sonst ist es nur ein Typ . Es kann keine Nicht-Vorlage sein, solange seine Basis magisch ist. (Die Basis kann eine Vorlage sein Instanziierung , wenn Sie scheinen zu wollen , die Basis der Funktionalität aufrecht zu erhalten als Vorlage .)

Leichtigkeitsrennen im Orbit
quelle
3
#include<iostream>

using namespace std;

template<class t> 
class base {
protected:
    t a;
public:
    base(t aa){
        a = aa;
        cout<<"base "<<a<<endl;
    }
};

template <class t> 
class derived: public base<t>{
    public:
        derived(t a): base<t>(a) {
        }
        //Here is the method in derived class 
    void sampleMethod() {
        cout<<"In sample Method"<<endl;
    }
};

int main() {
    derived<int> q(1);
    // calling the methods
    q.sampleMethod();
}
Narendra Kumawat
quelle
Was wäre, wenn Sie Methoden in der abgeleiteten Klasse hätten? Wie würden Sie sie definieren? Und die meisten importieren noch, zumindest für mich, wie rufen Sie diese Methoden in Ihrer main () -Funktion auf / verwenden sie?
Pototo
6
Erstens ist dies eine wirklich alte Frage, die bereits eine gute Antwort hat. Zweitens vermeiden Sie bitte Antworten (und Fragen), die nur Code sind. Es ist nützlich, auch detaillierte Erklärungen beizufügen.
Marcman