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

2024-02-19

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

为了用一个简单的例子来说明我的问题,我想要一个苹果、橙子和香蕉的类,它们都具有相同的操作和相同的实现。我希望它们有不同的类型,因为我想通过类型安全来避免错误。

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、模板、继承...)可以让我轻松地拥有具有不同类型的相同类?


一种常见的技术是拥有一个类模板,其中模板参数仅充当唯一标记(“标签”)以使其成为唯一类型:

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

请注意,标签类甚至不需要定义,就足够了declare唯一的类型名称。这是有效的,因为标签实际上是used模板中的任何位置。并且您可以声明类型名称inside模板参数列表(向@Xeo 致敬)。

The 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>;
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++中如何为同一个类定义不同的类型 的相关文章

随机推荐

  • 为什么 easeljs stage.getBounds() 返回 null?

    在这个例子中 var canvas document getElementById testCanvas var stage new createjs Stage canvas function drawRectangle var rect
  • 当我们在键盘上键入时,如何使字符串的内容显示在屏幕上?

    我有这个功能 玩家可以输入他的名字 但我希望每个字母在他输入时出现在屏幕上 这是我的功能 def input player name player name screen True name win blit player name bg
  • Spring Security,安全访问和非安全访问

    我正在做一个需要先登录的小应用程序 但对于某些第三方工具 我想提供一个不需要登录的API 登录本身工作正常 API 本身工作正常 但我不知道如何告诉 Spring Security 无需身份验证即可访问 API 我在这里和其他网站上检查了几
  • Spring mvc 验证异常处理程序在控制器方法之前调用

    我有以下代码 public class StudentController extends BaseController RequestMapping value student edit method RequestMethod POST
  • Flask-Sqlalchemy:数据库查询不返回新数据

    我正在构建一个应用程序 它从一项服务接收 webhook 将数据存储在数据库中 然后通过 API 提供数据 我能够成功地将数据添加到我的应用程序中 但是当我查询数据库时 我只收到上次启动应用程序时数据库中的第一次提交 例如 如果我启动应用程
  • Android:ListView 中的按钮未接收 onClick 事件

    我正在制作一个日期选择器活动 看起来像滚动的 30 天月份 日历 想想 Outlook 日历 日期选择器包含 MonthView 视图的 ListView 用于滚动 每个视图都是各个日期的 TableView MonthView 中的每一天
  • FPGA 有哪些实际应用?

    我对我的程序为一个小型七段显示器提供动力感到非常兴奋 但是当我向不在现场的人展示它时 他们总是说 那么你能用它做什么 我永远无法给他们一个简洁的答案 谁能帮我吗 第一 它们不需要具有易失性存储器 事实上 大厂商 Xilinx Altera
  • 如何从输出迭代器获取值类型?

    假设我有一个 C 容器 例如 MyContainer 包含的对象存储为void 指针 迭代此容器元素的唯一方法是通过两个接口函数 getFirstElem MyContainer const void 输出容器的第一个元素 getNextE
  • 为什么组件中的 React Native 函数没有“function”关键字?

    在 javascript 函数中声明为function myFuncName 但 React React Native 函数省略了该关键字 这是 ES6 JSX 或 React 特有的吗 这是ES6的一个特性 更多信息请访问https ba
  • C#/ODP.NET:大 IN 子句解决方法

    我们有一个 C 组件 可以处理将任意大小的元素列表附加到半任意 SQL 的 IN 子句中SELECT查询 本质上这可以归结为接收类似的东西 SELECT COUNT FROM a WHERE b IN 其中 是允许组件修改的查询的唯一部分
  • Python - 将日期戳添加到文本文件

    在Python v2中 有没有办法获取日期 时间戳并将其放入创建新的文本文件中 IE 当我想创建一个新的文本文件并将程序的内容写入其中时 它将创建一个包含时间 日期的新文本文件 谢谢你的帮助 import datetime def time
  • Google API oauth httpd 服务器与 Python 中的 SABNzbd+ 冲突

    我正在编写一个与 Google API 交互的 Python 应用程序 并需要通过 oauth2 进行用户身份验证 我目前正在设置一个本地身份验证服务器 以接收从 Google 的 oauth 服务器返回的 oauth2 身份验证代码 基本
  • 在 IE8 中可单击带警报的禁用按钮(Asp.net 网站中的浏览器兼容性问题)

    我已经禁用了链接按钮和图像按钮 位于链接按钮内 以便我可以显示警报 并且它在 Chrome 中工作正常 但是当我在 IE8 中打开它时 图像被禁用 但是当我单击它时 它会显示popup 您确定要删除该用户吗 为什么我在 IE8 和 IE7
  • ClassNotFoundException:使用服务组合时未找到 com.mysql.jdbc.Driver

    我正在使用 servicemix 4 4 1 和 maven 3 0 4 我对 servicemix java 世界非常陌生 我的主要知识是 c php 我已将以下内容添加到我的路线之一
  • 恢复后在 Android 中丢失 OpenGL 纹理

    我的游戏运行正常 除非我按下 HOME 按钮然后继续 需要做什么才能再次使用纹理 我尝试在 GLSurfaceView 上调用 onPause 和 onResume 当调用活动的 onPause 和 onResume 时 有什么想法我可能做
  • WCF MSMQ 单元测试

    我使用 WCF 创建了一个自定义 msmq 服务 它使用自定义绑定 因为它需要在通道层执行一些自定义逻辑 在通道层调用另一个 wcf 服务 该服务将成为未来几年我们系统的核心功能 我想尽我所能确保服务稳健 但是 我不知道从哪里开始 即测试响
  • 为什么.NET的条件属性会导致副作用被消除?

    我读到了关于Conditional今天的属性 根据 MSDN 正在申请ConditionalAttribute方法的调用指示编译器不应将对该方法的调用编译为 Microsoft 中间语言 MSIL 除非与关联的条件编译符号Condition
  • 使用'printf'在C中打印%符号[重复]

    这个问题在这里已经有答案了 我正在尝试打印一个 标志使用printf https en wikipedia org wiki Printf format string 我尝试过但没有运气 printf 我确信这真的很简单 但我刚刚开始使用
  • 如何提示内容管理器选择器直接在 ACTION_OPEN_DOCUMENT_TREE 的可选位置上打开

    当你使用ACTION OPEN DOCUMENT TREE要选择在 Android 11 中存储文件的路径的权限 默认情况下 默认的 Android 内容管理器会在最近使用的路径和按钮上打开 使用此文件夹 由于某种原因 即使该路径是可访问路
  • C++中如何为同一个类定义不同的类型

    我希望有几种类型共享相同的实现 但在 C 中仍然是不同的类型 为了用一个简单的例子来说明我的问题 我想要一个苹果 橙子和香蕉的类 它们都具有相同的操作和相同的实现 我希望它们有不同的类型 因为我想通过类型安全来避免错误 class Appl