Ereditare da una classe template in c ++


106

Supponiamo di avere una classe modello Area, che ha una variabile membroT area , a T getArea()e void setArea(T)funzioni membro.

Posso creare un file Area oggetto di un tipo specifico digitando Area<int>.

Ora ho una classe Rectangleche eredita la Areaclasse. DaRectangle sé non è un modello, non posso digitare Rectangle<int>.

Come specializzo gli ereditati Area tipo per gli Rectangleoggetti?

EDIT: Scusa, ho dimenticato di chiarire: la mia domanda è se sia possibile ereditare Area senza specializzarla, quindi non è ereditata come Area di int ma come Area Rectangle può specializzare i tipi per.


3
È un modello di classe , perché è un modello da cui vengono generate le classi.
sbi

1
@sbi Non ho intenzione di iniziare una guerra con le fiamme qui, ma se Bjarne Stroustrup non fa una distinzione tra modello di classe e classe modello (vedi The C ++ Programming Language , 4a ed., sezione 23.2.1), allora non dovresti neanche.
Michael Warner

@MichaelWarner Mi sembra di ricordare che ha fatto la distinzione. Tuttavia, erano gli anni '90 su Usenet. Forse da allora si è arreso. (O forse si riferisce a un modello di classe istanziato come a una classe modello?)
sbi

Risposte:


244

Per comprendere i modelli, è di enorme vantaggio ottenere la terminologia diretta perché il modo in cui ne parli determina il modo in cui pensarli.

In particolare, Areanon è una classe modello, ma un modello di classe. Cioè, è un modello da cui è possibile generare classi. Area<int>è una tale classe ( non è un oggetto, ma ovviamente puoi creare un oggetto da quella classe nello stesso modo in cui puoi creare oggetti da qualsiasi altra classe). Un'altra classe simile sarebbe Area<char>. Si noti che quelle sono classi completamente diverse, che non hanno nulla in comune tranne il fatto che sono state generate dallo stesso modello di classe.

Poiché Areanon è una classe, non puoi derivarne la classe Rectangle. Puoi solo derivare una classe da un'altra classe (o più di esse). Poiché Area<int>è una classe, potresti, ad esempio, derivarne Rectangle:

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

Poiché Area<int>e Area<char>sono classi diverse, puoi anche derivare da entrambe contemporaneamente (tuttavia quando accedi ai membri di esse, dovrai affrontare le ambiguità):

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

Tuttavia è necessario specificare da quale classe derivare quando si definisce Rectangle. Questo è vero indipendentemente dal fatto che quelle classi siano generate da un modello o meno. Due oggetti della stessa classe semplicemente non possono avere gerarchie di ereditarietà diverse.

Quello che puoi fare è creare anche Rectangleun modello. Se scrivi

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

Hai un modello Rectangleda cui puoi ottenere una classe da Rectangle<int>cui deriva Area<int>e una classe diversa da Rectangle<char>cui deriva Area<char>.

È possibile che tu voglia avere un solo tipo in Rectanglemodo da poter passare tutti i tipi di Rectanglealla stessa funzione (che di per sé non ha bisogno di conoscere il tipo di Area). Poiché le Rectangle<T>classi generate dall'istanza del modello Rectanglesono formalmente indipendenti l'una dall'altra, non funziona in questo modo. Tuttavia puoi utilizzare l'ereditarietà multipla qui:

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);
}

Se è importante che il tuo generico Rectanglederivi da un generico Area, puoi fare lo stesso trucco Areaanche con :

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
};

Nota: un parametro del tipo di modello fa parte della classe di un oggetto che istanzia quel modello di classe. In altre parole, non è un componente della classe, è parte del tipo.
Nikos

21

Stai solo cercando di derivare da Area<int>? In tal caso fai questo:

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

MODIFICA: in seguito al chiarimento, sembra che tu stia effettivamente cercando di creare anche Rectangleun modello, nel qual caso dovrebbe funzionare quanto segue:

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


8

Trasforma Rectangle in un modello e passa il nome del tipo ad Area:

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

};

6

Rectangledovrà essere un modello, altrimenti è solo un tipo . Non può essere un non modello mentre la sua base lo è magicamente. (La sua base potrebbe essere un'istanza del modello , anche se sembra che tu voglia mantenere la funzionalità della base come modello .)


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();
}

e se avessi metodi nella classe derivata? Come li definiresti? E la maggior parte importa ancora, almeno per me, come chiami / usi questi metodi nella tua funzione main ()?
Pototo

6
Innanzitutto, questa è una domanda davvero vecchia che ha già un'ottima risposta. Secondo, evita risposte (e domande) che sono solo codice. È utile includere anche spiegazioni dettagliate.
marcman
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.