我想有几种类型共享相同的实现,但在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 {};
但是,构造函数不是继承的,我必须重写它们。
是否有任何机制(typedef,templates,inheritance ...)可以让我轻松拥有不同类型的同一个类?
答案 0 :(得分:118)
一种常见的技术是使用一个类模板,其中模板参数只是作为唯一标记(“标记”)使其成为唯一类型:
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>;
答案 1 :(得分:19)
使用模板,并对每个水果使用 trait ,例如:
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;
可能有点矫枉过正! ;)
答案 2 :(得分:14)
template<class Derived> class Fruit;
答案 3 :(得分:6)