Mewarisi dari kelas template di c ++

106

Katakanlah kita memiliki kelas template Area, yang memiliki variabel anggota T area, seorang T getArea()dan void setArea(T)fungsi anggota.

Saya dapat membuat Areaobjek dengan tipe tertentu dengan mengetik Area<int>.

Sekarang saya memiliki kelas Rectangleyang mewarisi Areakelas tersebut. Karena Rectangleitu sendiri bukan template, saya tidak bisa mengetik Rectangle<int>.

Bagaimana cara saya mengkhususkan Areatipe yang diwariskan untuk Rectangleobjek?

EDIT: Maaf, saya lupa menjelaskan - pertanyaan saya adalah apakah mungkin mewarisi Area tanpa mengkhususkannya, jadi tidak diwariskan sebagai Area int tetapi karena Persegi Panjang Area dapat mengkhususkan tipe untuk.

dtech
sumber
3
Ini adalah template kelas , karena ini adalah template tempat kelas dibuat.
sbi
1
@sbi Saya tidak bermaksud untuk memulai perang api di sini, tetapi jika Bjarne Stroustrup tidak membuat perbedaan antara template kelas dan kelas template (lihat The C ++ Programming Language , edisi ke-4, bagian 23.2.1), maka Anda tidak boleh juga tidak.
Michael Warner
@MichaelWarner Sepertinya saya ingat dia membuat perbedaan. Itu terjadi di tahun 90-an, di Usenet. Mungkin dia sudah menyerah sejak itu. (Atau mungkin dia merujuk ke template kelas yang dipakai sebagai kelas template?)
sbi

Jawaban:

244

Untuk memahami template, sangat bermanfaat untuk meluruskan terminologinya karena cara Anda membicarakannya menentukan cara memikirkannya.

Secara khusus, Areaini bukan kelas template, tapi template kelas. Artinya, ini adalah template tempat kelas dapat dibuat. Area<int>adalah kelas seperti itu (ini bukan objek, tetapi tentu saja Anda dapat membuat objek dari kelas itu dengan cara yang sama seperti Anda membuat objek dari kelas lain). Kelas lain seperti itu Area<char>. Perhatikan bahwa itu adalah kelas yang sama sekali berbeda, yang tidak memiliki kesamaan apa pun kecuali fakta bahwa mereka dihasilkan dari template kelas yang sama.

Karena Areabukan kelas, Anda tidak dapat memperoleh kelas Rectangledarinya. Anda hanya dapat memperoleh satu kelas dari kelas lain (atau beberapa di antaranya). Karena Area<int>merupakan sebuah kelas, Anda dapat, misalnya, mengambil Rectangledarinya:

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

Karena Area<int>dan Area<char>merupakan kelas yang berbeda, Anda bahkan dapat mengambil keduanya pada saat yang sama (namun saat mengakses anggota mereka, Anda harus berurusan dengan ambiguitas):

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

Namun Anda harus menentukan kelas mana yang akan diturunkan saat Anda menentukan Rectangle. Ini benar tidak peduli apakah kelas-kelas itu dihasilkan dari template atau tidak. Dua objek dari kelas yang sama tidak dapat memiliki hierarki pewarisan yang berbeda.

Yang bisa Anda lakukan adalah membuat Rectangletemplate juga. Jika Anda menulis

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

Anda memiliki template Rectangledari mana Anda bisa mendapatkan kelas Rectangle<int>asal Area<int>, dan kelas lain Rectangle<char>asal Area<char>.

Mungkin Anda ingin memiliki satu tipe Rectanglesehingga Anda bisa meneruskan semua jenis Rectangleke fungsi yang sama (yang tidak perlu mengetahui tipe Area). Karena Rectangle<T>kelas yang dibuat dengan membuat contoh template Rectanglesecara formal tidak bergantung satu sama lain, cara kerjanya tidak seperti itu. Namun Anda dapat menggunakan beberapa warisan di sini:

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

Jika penting bahwa generik Anda Rectanglediturunkan dari generik, AreaAnda juga dapat melakukan trik yang sama 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
sumber
Catatan: Parameter jenis template adalah bagian dari kelas suatu objek yang membuat contoh template kelas itu. Dengan kata lain, ini bukan komponen kelas, itu bagian dari tipe.
Nikos
21

Apakah Anda hanya mencoba untuk mendapatkan dari Area<int>? Dalam hal ini Anda melakukan ini:

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

EDIT: Setelah klarifikasi, tampaknya Anda benar-benar mencoba membuat Rectangletemplate juga, dalam hal ini yang berikut ini akan berfungsi:

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

Jadikan Rectangle sebagai template dan berikan nama jenis ke Area:

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

};
pezcode
sumber
6

Rectangleharus berupa template, jika tidak maka hanya satu jenis . Itu tidak bisa menjadi non-template sementara basisnya secara ajaib. (Basisnya mungkin merupakan contoh templat , meskipun Anda tampaknya ingin mempertahankan fungsionalitas basis sebagai templat .)

Balapan Ringan dalam Orbit
sumber
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
sumber
bagaimana jika Anda memiliki metode di kelas turunan? Bagaimana Anda mendefinisikannya? Dan sebagian besar mengimpor, setidaknya bagi saya, bagaimana Anda memanggil / menggunakan metode tersebut dalam fungsi main () Anda?
Pototo
6
Pertama, ini adalah pertanyaan lama yang sudah memiliki jawaban bagus. Kedua, harap hindari jawaban (dan pertanyaan) yang hanya berupa kode. Berguna juga untuk memasukkan penjelasan rinci.
marcman