Herdando de uma classe de modelo em c ++

106

Vamos dizer que temos uma classe de modelo Area, que tem uma variável de membro T area, um T getArea()e um void setArea(T)membro funções.

Posso criar um Areaobjeto de um tipo específico digitando Area<int>.

Agora eu tenho uma classe Rectangleque herda a Areaclasse. Já que Rectangleele mesmo não é um modelo, não posso digitar Rectangle<int>.

Como posso especializar o Areatipo herdado para Rectangleobjetos?

EDIT: Desculpe, esqueci de esclarecer - minha dúvida é se é possível herdar Área sem especializá-la, então não é herdada como Área de ints, mas como Retângulo de Área pode especializar os tipos para.

dtech
fonte
3
É um modelo de classe , porque é um modelo a partir do qual as classes são geradas.
sbi de
1
@sbi Não pretendo iniciar uma guerra violenta aqui, mas se Bjarne Stroustrup não fizer uma distinção entre modelo de classe e classe de modelo (consulte The C ++ Programming Language , 4ª ed., seção 23.2.1), então você não deveria também não.
Michael Warner,
@MichaelWarner Parece que me lembro dele fazendo a distinção. Isso foi nos anos 90, no entanto, na Usenet. Talvez ele tenha desistido desde então. (Ou talvez ele se refira a um modelo de classe instanciado como uma classe de modelo?)
sbi

Respostas:

244

Para entender os modelos, é uma grande vantagem definir a terminologia correta, porque a maneira como você fala sobre eles determina a maneira de pensar sobre eles.

Especificamente, Areanão é uma classe de modelo, mas um modelo de classe. Ou seja, é um modelo a partir do qual as classes podem ser geradas. Area<int>é tal classe um (é não um objeto, mas é claro que você pode criar um objeto dessa classe da mesma forma que você pode criar objetos a partir de qualquer outra classe). Outra classe seria Area<char>. Observe que essas são classes completamente diferentes, que não têm nada em comum, exceto pelo fato de que foram geradas a partir do mesmo modelo de classe.

Como Areanão é uma classe, você não pode derivar a classe Rectangledela. Você só pode derivar uma classe de outra classe (ou de várias delas). Como Area<int>é uma classe, você poderia, por exemplo, derivar Rectangledela:

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

Como Area<int>e Area<char>são classes diferentes, você pode até derivar de ambas ao mesmo tempo (no entanto, ao acessar membros delas, você terá que lidar com ambigüidades):

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

No entanto, você deve especificar de qual classe derivar ao definir Rectangle. Isso é verdade, não importa se essas classes são geradas a partir de um modelo ou não. Dois objetos da mesma classe simplesmente não podem ter hierarquias de herança diferentes.

O que você pode fazer é criar Rectangleum modelo também. Se você escrever

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

Você tem um modelo Rectangledo qual pode obter uma classe Rectangle<int>que deriva de Area<int>e uma classe diferente Rectangle<char>que deriva Area<char>.

Pode ser que você queira ter um único tipo Rectangle para que possa passar todos os tipos de Rectanglepara a mesma função (que por si só não precisa saber o tipo de Área). Como as Rectangle<T>classes geradas pela instanciação do modelo Rectanglesão formalmente independentes umas das outras, isso não funciona. No entanto, você pode usar a herança múltipla aqui:

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 for importante que o seu genérico Rectangleseja derivado de um genérico, Areavocê também pode fazer o mesmo com Area:

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
fonte
Nota: Um parâmetro de tipo de modelo é parte da classe de um objeto que instancia esse modelo de classe. Em outras palavras, não é um componente da classe, faz parte do tipo.
Nikos
21

Você está apenas tentando derivar Area<int>? Nesse caso, você faz isso:

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

EDITAR: Após o esclarecimento, parece que você está realmente tentando fazer Rectangleum modelo também; nesse caso, o seguinte deve funcionar:

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

Transforme o retângulo em um modelo e passe o nome do tipo para a área:

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

};
pezcode
fonte
6

Rectangleterá que ser um modelo, caso contrário, é apenas um tipo . Não pode ser um não-modelo enquanto sua base é magicamente. (Sua base pode ser uma instanciação de modelo , embora você pareça querer manter a funcionalidade da base como um modelo .)

Lightness Races in Orbit
fonte
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
fonte
e se você tivesse métodos na classe derivada? Como você os definiria? E a maioria ainda importa, pelo menos para mim, como você chama / usa esses métodos em sua função main ()?
Pototo
6
Em primeiro lugar, esta é uma pergunta muito antiga que já tem uma ótima resposta. Em segundo lugar, evite respostas (e perguntas) que sejam apenas códigos. É útil incluir explicações detalhadas também.
marcman