如何在C ++中为同一个类定义不同的类型 [英] How to define different types for the same class in C++

查看:142
本文介绍了如何在C ++中为同一个类定义不同的类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



为了用一个简单的例子说明我的问题,喜欢有一个类苹果,橘子和香蕉,所有具有相同的操作和相同的实现。我希望它们有不同的类型,因为我想避免错误由于类型安全。

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

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

Orange ...

为了不重复代码,看起来像我可以使用基类Fruit继承自:

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

苹果:public Fruit {};
class Banana:public Fruit {};
class Orange:public Fruit {};

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



有没有任何机制(typedefs,模板,继承...),这将允许我很容易有不同类型的同一个类?

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

使用Apple = Fruit< struct AppleTag> ;;
使用Banana = Fruit< struct BananaTag> ;;

请注意,标签类甚至不需要定义,足以声明唯一的类型名称。这是因为在模板中的任何位置实际上都使用了 标签。您可以在模板参数列表中声明类型名称​​。



使用 语法是C ++ 11。如果你使用C ++ 03,请改为:

  typedef Fruit< struct AppleTag>苹果; 






如果常用功能占用大量代码这不幸地在最终的可执行文件中引入了很多重复的代码。这可以通过使用一个公共基类实现该功能,然后具有从它派生的专业化(你实际上实例化)来防止。



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

  //实际的水果类保持不变,模板声明除外
template< typename Tag,typename = Tag>
class Fruit {/ * unchanged * /};

template< typename T>
class Fruit< T,T> :public Fruit< T,void> {
public:
//应该工作,但不在我的编译器:
//使用水果< T,void> :: Fruit;
Fruit(int p):Fruit< T,void>(p){}
};

使用Apple = Fruit< struct AppleTag> ;;
使用Banana = Fruit< struct BananaTag> ;;


I would like to have several types that share the same implementation but still are of different type in C++.

To illustrate my question with a simple example, I would like to have a class for Apples, Oranges and Bananas, all having the same operations and same implementation. I would like them to have different types because I want to avoid errors thanks to type-safety.

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 ...

In order not duplicating code, it looks like I could use a base class Fruit and inherit from it:

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

But then, the constructors are not inherited and I have to rewrite them.

Is there any mechanism (typedefs, templates, inheritance...) that would allow me to easily have the same class with different types?

解决方案

A common technique is to have a class template where the template argument simply serves as a unique token ("tag") to make it a unique type:

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

Note that the tag classes don’t even need to be defined, it’s enough to declare a unique type name. This works because the tag isn’s actually used anywhere in the template. And you can declare the type name inside the template argument list (hat tip to @Xeo).

The using syntax is C++11. If you’re stuck with C++03, write this instead:

typedef Fruit<struct AppleTag> Apple;


If the common functionality takes up a lot of code this unfortunately introduces quite a lot of duplicate code in the final executable. This can be prevented by having a common base class implementing the functionality, and then having a specialisation (that you actually instantiate) that derives from it.

Unfortunately, that requires you to re-implement all non-inheritable members (constructors, assignment …) which adds a small overhead itself – so this only makes sense for large classes. Here it is applied to the above example:

// 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>;

这篇关于如何在C ++中为同一个类定义不同的类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆