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

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

问题描述

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

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

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

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

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

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.

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

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

注意,标签类甚至不需要定义,只要声明一个唯一的类型名称就足够了.这是有效的,因为标签实际上在模板中的任何地方使用.您可以在模板参数列表中声明类型名称​​inside(给@Xeo 的提示).

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

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

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天全站免登陆