85

同じ実装を共有するいくつかの型が必要ですが、C++ では型が異なります。

簡単な例で私の質問を説明するために、同じ操作と同じ実装を持つ、リンゴ、オレンジ、バナナのクラスを作成したいと思います。タイプセーフのおかげでエラーを回避したいので、それらに異なるタイプを持たせたいと思います。

class Apple {
     int p;
public:
     Apple (int p) : p(p) {}
     int price () const {return p;}
}

class Banana {
     int p;
public:
     Banana (int p) : p(p) {}
     int price () const {return p;}
}

class Orange ...

コードを複製しないために、基本クラス Fruit を使用して継承できるようです。

class Fruit {
     int p;
public:
     Fruit (int p) : p(p) {}
     int price () const {return p;}
}

class Apple: public Fruit {};
class Banana: public Fruit {};
class Orange: public Fruit {};

しかし、コンストラクタは継承されず、書き直さなければなりません。

同じクラスを異なる型で簡単に持つことができるメカニズム (typedef、テンプレート、継承など) はありますか?

4

4 に答える 4

120

一般的な手法は、テンプレート引数が単に一意のトークン (「タグ」) として機能するクラス テンプレートを使用して、一意の型にすることです。

template <typename Tag>
class Fruit {
    int p;
public:
    Fruit(int p) : p(p) { }
    int price() const { return p; }
};

using Apple = Fruit<struct AppleTag>;
using Banana = Fruit<struct BananaTag>;

タグ クラスを定義する必要さえないことに注意してください。一意の型名を宣言するだけで十分です。タグは実際にはテンプレートのどこでも使用されているため、これは機能します。また、テンプレート引数リスト内で型名を宣言できます(@Xeo へのヒント)。

構文はusingC++11 です。C++03 で行き詰まっている場合は、代わりに次のように記述します。

typedef Fruit<struct AppleTag> Apple;

共通の機能が多くのコードを占有する場合、残念ながら、最終的な実行可能ファイルにかなりの重複コードが導入されます。これは、機能を実装する共通の基本クラスを持ち、そこから派生する特殊化 (実際にインスタンス化する) を持つことで防ぐことができます。

残念ながら、それには継承不可能なすべてのメンバー (コンストラクター、代入など) を再実装する必要があり、それ自体にわずかなオーバーヘッドが追加されるため、これは大きなクラスの場合にのみ意味があります。ここでは、上記の例に適用されます。

// Actual `Fruit` class remains unchanged, except for template declaration
template <typename Tag, typename = Tag>
class Fruit { /* unchanged */ };

template <typename T>
class Fruit<T, T> : public Fruit<T, void> {
public:
    // Should work but doesn’t on my compiler:
    //using Fruit<T, void>::Fruit;
    Fruit(int p) : Fruit<T, void>(p) { }
};

using Apple = Fruit<struct AppleTag>;
using Banana = Fruit<struct BananaTag>;
于 2013-01-09T09:50:53.817 に答える
19

テンプレートを使用し、果物ごとに特性を使用します。次に例を示します。

struct AppleTraits
{
  // define apple specific traits (say, static methods, types etc)
  static int colour = 0; 
};

struct OrangeTraits
{
  // define orange specific traits (say, static methods, types etc)
  static int colour = 1; 
};

// etc

Fruit次に、この特性で型付けされる単一のクラスを作成します。

template <typename FruitTrait>
struct Fruit
{
  // All fruit methods...
  // Here return the colour from the traits class..
  int colour() const
  { return FruitTrait::colour; }
};

// Now use a few typedefs
typedef Fruit<AppleTraits> Apple;
typedef Fruit<OrangeTraits> Orange;

少しやり過ぎかもしれません!;)

于 2013-01-09T09:51:57.997 に答える
14
于 2013-01-09T09:49:20.137 に答える
6

BOOST_STRONG_TYPEDEFもあります。

于 2013-01-16T07:00:26.940 に答える