85

我希望有几种类型共享相同的实现,但在 C++ 中仍然是不同的类型。

为了用一个简单的例子来说明我的问题,我想为 Apples、Oranges 和 Bananas 创建一个类,它们都具有相同的操作和相同的实现。我希望它们具有不同的类型,因为由于类型安全,我想避免错误。

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

但是,构造函数不是继承的,我必须重写它们。

是否有任何机制(类型定义、模板、继承......)可以让我轻松地拥有具有不同类型的同一个类?

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 的提示)。

using语法是 C++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
  • C++11 将允许构造函数继承:使用 C++ 基类构造函数?
  • 否则,您可以使用模板来实现相同的目的,例如template<class Derived> class Fruit;
于 2013-01-09T09:49:20.137 回答
6

还有BOOST_STRONG_TYPEDEF

于 2013-01-16T07:00:26.940 回答