如何在C++中为同一个类定义不同的类型

anu*_*umi 83 c++ types

我想有几种类型共享相同的实现,但在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 ...
Run Code Online (Sandbox Code Playgroud)

为了不复制代码,看起来我可以使用基类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 {};
Run Code Online (Sandbox Code Playgroud)

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

是否有任何机制(typedef,templates,inheritance ...)可以让我轻松拥有不同类型的同一个类?

Kon*_*lph 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>;
Run Code Online (Sandbox Code Playgroud)

请注意,甚至不需要定义标记类,它足以声明唯一的类型名称.这是有效的,因为标签实际上并未在模板中的任何位置使用.你可以声明的类型名称里面的模板参数列表(帽尖到@Xeo).

该using语法是C++ 11.如果您坚持使用C++ 03,请改为编写:

typedef Fruit<struct AppleTag> Apple;
Run Code Online (Sandbox Code Playgroud)

如果常见功能占用了大量代码,那么不幸的是,在最终的可执行文件中引入了相当多的重复代码.这可以通过具有实现该功能的公共基类,然后具有从中派生的特化(您实际实例化)来防止.

不幸的是,这需要你重新实现所有不可继承的成员(构造函数,赋值...),这会增加一些小的开销 - 所以这只适用于大类.这里它适用于上面的例子:

// 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>;
Run Code Online (Sandbox Code Playgroud)

  • 实际上你可以在模板参数列表中声明它们,我发现这很方便:`Fruit <struct SomeTag>`. (20认同)
  • 不利的一面是针对不同类型的模板实例的多次发射。这些重复项是否已被广泛使用的链接器消除? (2认同)

Nim*_*Nim 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
Run Code Online (Sandbox Code Playgroud)

然后有一个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;
Run Code Online (Sandbox Code Playgroud)

可能有点矫枉过正!;)


Sam*_*Sam 14

  • C++ 11将允许构造函数继承:使用C++基类构造函数?
  • 否则,您可以使用模板来实现相同的功能,例如 template<class Derived> class Fruit;