web-dev-qa-db-ja.com

C ++のテンプレートクラスから継承する

メンバークラスT areaT getArea()、およびvoid setArea(T)メンバー関数を持つテンプレートクラスAreaがあるとします。

Area<int>と入力することにより、特定のタイプのAreaオブジェクトを作成できます。

これで、Rectangleクラスを継承するAreaクラスができました。 Rectangle自体はテンプレートではないため、Rectangle<int>と入力することはできません。

Areaオブジェクトの継承されたRectangleタイプをどのように特化できますか?

編集:申し訳ありませんが、明確にするのを忘れました-私の質問は、エリアを特殊化せずに継承できるかどうかです。したがって、エリアのintとして継承されませんが、エリアレクタングルはタイプを特殊化できるためです。

89
dtech

テンプレートを理解するためには、用語を明確にすることが非常に有利です。なぜなら、テンプレートについて話す方法がテンプレートについて考える方法を決定するからです。

具体的には、Areaはテンプレートクラスではなく、クラステンプレートです。つまり、クラスを生成できるテンプレートです。 Area<int>はそのようなクラスです(notオブジェクトですが、もちろん、他のクラスからオブジェクトを作成するのと同じ方法で、そのクラスからオブジェクトを作成できます)。別のそのようなクラスはArea<char>です。これらは完全に異なるクラスであり、同じクラステンプレートから生成されたという事実を除き、共通点はありません。

Areaはクラスではないため、クラスRectangleを派生することはできません。クラスは、別のクラス(またはそれらのいくつか)からのみ派生できます。 Area<int>はクラスであるため、たとえば、Rectangleを派生させることができます。

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

Area<int>Area<char>は異なるクラスであるため、両方から同時に派生させることもできます(ただし、それらのメンバーにアクセスする場合は、あいまいさに対処する必要があります)。

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

ただし、Rectangleを定義するときに、派生元のクラスを指定する必要があります。これは、これらのクラスがテンプレートから生成されたかどうかに関係なく当てはまります。同じクラスの2つのオブジェクトは、異なる継承階層を持つことはできません。

できることは、Rectangleもテンプレートにすることです。書いたら

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

テンプレートRectangleがあり、そこからRectangle<int>から派生したクラスArea<int>と、Rectangle<char>から派生した別のクラスArea<char>を取得できます。

すべての種類のRectangleを同じ関数に渡すことができるように、単一のタイプRectangleが必要な場合があります(それ自体はAreaタイプを知る必要はありません)。テンプレートRectangleをインスタンス化することで生成されるRectangle<T>クラスは形式的に互いに独立しているため、そのようには機能しません。ただし、ここで複数の継承を利用できます。

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

ジェネリックRectangleがジェネリックAreaから派生していることが重要な場合は、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
};
206
celtschk

Area<int>から派生させようとしていますか?その場合、これを行います:

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

編集:明確化に続いて、実際にRectangleもテンプレートにしようとしているようです。この場合、次のように動作します:

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

Rectangleをテンプレートにして、タイプ名をAreaに渡します。

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

};
8
pezcode
class Rectangle : public Area<int> {
};
8
ldanko

Rectangleはテンプレートである必要があります。それ以外の場合は、1つのタイプのみです。そのベースは魔法のようですが、非テンプレートにすることはできません。 (そのベースはテンプレートインスタンス化かもしれませんが、ベースの機能を維持したいようですテンプレートとして。)

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