C++ 中的映射可以接受任何类型的值

2023-12-13

我想在 c++ 中创建一个可以接受任何类型值的映射,我在 java 中使用 Object 类做了同样的事情 映射但不知道如何在 C++ 中执行此操作。 请帮忙。


正如前面的答案正确建议的那样,您不能在 C++ 中开箱即用。我假设通过“[...]可以接受任何类型的值[...]”你指的是地图的值,而不是键。

不过,这是您可以做的。你有两个选择;我要从丑变美

第一种方法:

  • 创建一个您将用作的值持有类value对于地图。我们就这样称呼它吧Value.

  • 在该类中为您想要支持的所有类型实现显式构造函数,并跟踪该类当前存储的值的类型

  • 从映射中获取值后检查值的类型并使用适当的 getter 函数

  • 可选地,超载<<支持标准流的运算符

有关示例实现,请参阅以下代码:

#include <iostream>
#include <memory>
#include <map>

class Value {
public:
  typedef enum {
    String,
    Integer,
    Double,
    Float
  } ContentType;

private:
  ContentType m_ctType;

  std::string m_strContent;
  int m_nContent;
  double m_dContent;
  float m_fContent;

public:
  Value() : m_strContent(""), m_ctType(String) {}
  explicit Value(const char* arrcString) : m_strContent(std::string(arrcString)), m_ctType(String) {}
  explicit Value(std::string strContent) : m_strContent(strContent), m_ctType(String) {}
  explicit Value(int nContent) : m_nContent(nContent), m_ctType(Integer) {}
  explicit Value(double dContent) : m_dContent(dContent), m_ctType(Double) {}
  explicit Value(float fContent) : m_fContent(fContent), m_ctType(Float) {}

  ~Value() {}

  ContentType type() {
    return m_ctType;
  }

  std::string stringValue() { return m_strContent; }
  int integerValue() { return m_nContent; }
  double doubleValue() { return m_dContent; }
  float floatValue() { return m_fContent; }
};

std::ostream& operator<<(std::ostream& osStream, Value& valOut) {
  switch(valOut.type()) {
  case Value::String: osStream << valOut.stringValue(); break;
  case Value::Integer: osStream << valOut.integerValue(); break;
  case Value::Double: osStream << valOut.doubleValue(); break;
  case Value::Float: osStream << valOut.floatValue(); break;
  }

  return osStream;
}

这可以像这样使用:

int main() {
  std::map<int, Value> mapAnyValue;

  mapAnyValue[0] = Value("Test");
  mapAnyValue[1] = Value(1337);

  std::cout << mapAnyValue[0] << ", " << mapAnyValue[1] << std::endl;

  return 0;
}

这输出

Test, 1337

现在有些人可能会说这是

  • 效率低下(它为不在每个中使用的类型保留了字段Value实例)
  • 难以扩展/维护(添加新字段有点麻烦)
  • 一般来说糟糕的设计

他们是对的。因此,这是使用多态性和模板的替代方案。

第二种方法:

这要求您在将值分配给变量时定义要存储的值的类型,并且需要使用指针。原因如下。

对于这种方法,我们执行以下操作:

  • 创建基类ValueBase作为一个类,我们可以将其放入地图中value type.

  • 从该类派生模板类Value<T>保存模板类型的任意值T.

  • 支持std::cout和朋友们,我们实现了一个运算符重载<<上课ValueBase,添加纯虚拟output功能为ValueBase,并重写此函数Value<T>使用默认值<<您在模板中使用的任何类型的运算符。

请参阅下面的代码示例:

#include <iostream>
#include <memory>
#include <map>

class ValueBase {
public:
  ValueBase() {}
  ~ValueBase() {}

  virtual void output(std::ostream& osStream) = 0;
};

template<typename T>
class Value : public ValueBase {
private:
  T m_tValue;

public:
  Value(T tValue) : m_tValue(tValue) {}
  ~Value() {}

  T value() {
    return m_tValue;
  }

  void output(std::ostream& osStream) override {
    osStream << m_tValue;
  }
};

std::ostream& operator<<(std::ostream& osStream, ValueBase& valOut) {
  valOut.output(osStream);

  return osStream;
}

这可以像这样使用:

int main() {
  std::map<int, std::shared_ptr<ValueBase>> mapAnyValue;

  mapAnyValue[0] = std::make_shared<Value<std::string>>("Test");
  mapAnyValue[1] = std::make_shared<Value<int>>(1337);

  std::cout << *mapAnyValue[0] << ", " << *mapAnyValue[1] << std::endl;

  return 0;
}

或者没有智能指针:

int main() {
  std::map<int, ValueBase*> mapAnyValue;

  mapAnyValue[0] = new Value<std::string>("Test");
  mapAnyValue[1] = new Value<int>(1337);

  std::cout << *mapAnyValue[0] << ", " << *mapAnyValue[1] << std::endl;

  delete mapAnyValue[0];
  delete mapAnyValue[1];

  return 0;
}

均输出

Test, 1337

第二种方法在使用方面存在一些差异。

首先,您需要使用指针。这样做的原因是,这样一来,成员函数vtable被保留,并且您可以从派生类重写基类中的函数。在我们的情况下,这意味着:当我们调用output()在类型指针上ValueBase被初始化为Value<T>, the output()函数来自Value<T>被使用而不是来自ValueBase。如果您使用普通变量而不是指针,output()函数来自ValueBase将被使用,并且我们会丢失派生类的信息。

其次,这与第一个相关,您需要引用使用该值时获得的指针。如果你想输出一个ValueBase or Value<T>指针与std::cout,你需要这样做std::cout << *var输出包含的值。如果你刚刚这样做了std::cout << var,您将正确地获得指针的地址。

我确信还有其他选择,特别是在使用时Boost,但我不是这方面的专家。其他人可能有更有价值的信息。

除此之外,你所做的事情听起来像是一种懒惰的行为。 C++ 拥有强类型系统是有原因的;它不仅定义良好,而且您还知道对代码的期望。如果你开始让事情变得模糊并使用任意容器对象来完成各种任务,你的代码将失去可读性、清晰度,并且(很可能)会产生大量难以跟踪、调试和最终修复的错误,因为您需要支持您引入的所有精美容器以保持框架运行。

如果你想使用Java这样的语言,最好使用Java而不是C++。

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

C++ 中的映射可以接受任何类型的值 的相关文章

随机推荐

  • 预提交时是否可以使用 ESlint 或其他任何方式禁止单词列表?

    我正在使用哈士奇来处理预提交的事情 所以在这里我希望新编写的程序不应包含单词列表 例如dangerouslySetInnerHTML etc 我知道有一个规则no danger在 eslint plugin react 中 但它只阻止了这个
  • Python 3 中的 PyEval_InitThreads:如何/何时调用它? (故事继续令人作呕)

    基本上好像有massive对确切时间的困惑 模糊PyEval InitThreads 应该被调用 以及需要哪些伴随的 API 调用 这Python 官方文档不幸的是非常含糊 已经有stackoverflow上有很多问题关于这个话题 事实上
  • AngularJS nvD3 错误 - 哪些版本兼容?

    我和这位用户有同样的问题 Angular nvD3 错误 指令 nvd3 的隔离范围定义无效 那里的答案说 使用最新的 AngularJS 超越 Angular 1 1 4 但我正在使用最新的 AngularJS AngularJS v1
  • 未正确显示

    我在显示时遇到问题 nbsp 在我的网页中 在 PHP 中使用 utf8 decode 后 它显示为 我一直在使用 我刚刚注意到 所有其他特殊字符 如
  • Javascript 对象键应该被引用吗?

    我知道有一些问题可能会提到这一点 但我没有找到任何与 javascript 严格相关的内容 例如这个 JSON Spec 密钥是否必须用引号引起来 但我的问题是 我们写的时候应该使用引号吗 JavaScript Object 我认为不加引号
  • 使用 Ember.js 过滤子记录(hasMany 关联)

    有没有可能过滤hasMany来自模型记录的记录 我想要获取按客户分组的活动项目 客户模型 Docket Customer DS Model extend name DS attr string initial DS attr string
  • Visual Studio Team Services Rest API 时增强的安全错误

    我目前正在尝试使用 Visual Studio Team Services 原 Visual Studio Online 公开的 Rest API 来获取工作项信息 我似乎能够连接 但是当我查看查询的响应时 它是一个带有增强安全错误消息的
  • MVC - 更改链接中 URL 的一部分

    我有一个支持本地化的网站 我希望能够在英语和法语之间切换 假设用户当前位于以下 URL http www example com en Home 我想重定向到 http www example com fr Home 如果用户单击 法语 链
  • 调用 [NSBundle mainBundle] 时 XCTest 失败

    我有一些代码可以调用 NSBundle mainBundle 在某些时候 主要是为了读取 设置首选项 当我对该方法进行单元测试时 测试失败 因为测试的 mainBundle 不包含该文件 This is 一个已知问题 苹果不会像他们认为的那
  • ssl_error_rx_record_too_long 和 Apache SSL [关闭]

    Closed 这个问题是无关 目前不接受答案 我有一位客户尝试访问我的网站之一 但他们不断收到此错误 gt ssl error rx record too long 他们在所有浏览器 所有平台上都会收到此错误 我根本无法重现这个问题 我和我
  • 来自我的本机 iPhone 应用程序的 linkedin 连接

    大家好 我是 iphone 开发新手 我想从我的本机 iphone 应用程序连接到 linkedin 我目前不知道如何连接到它 请指导我该怎么做 From http www zhangkf com 2010 06 linkedin deve
  • onclick() 函数可以不与调用它的元素同名吗? [复制]

    这个问题在这里已经有答案了 所以我有这个按钮元素 无论我做什么 它都会拒绝触发它的 onclick 函数 这让我发疯了一段时间
  • htaccess 重写 url,如 Stack Overflow

    Stack Overflow 生成重写 URL 所以我需要知道如何像 Stack Overflow 那样做到这一点 http stackoverflow com questions 9168364 how to rewrite seo fr
  • 在 foreach 循环中使用字符串变量检索图像资源

    我有一个字符串数组 abc 我把它放在 foreach 循环中 我想使用 foreach 循环中的值从资源中检索图像并将其放入图片框中 代码如下 char stringArr inputted ToCharArray foreach cha
  • 跨多个用户共享 BigQuery 的缓存

    据我了解 BigQuery 的caching机制是基于每个用户的 但我们希望能够在项目 数据集 表级别上共享缓存 例如 约翰和玛丽都在同一个 Google 项目上工作XYZ 他们喜欢使用 BigQuery 并且都查询表Bar在数据集中Foo
  • 我的rec函数是尾递归的吗?

    这个函数是尾递归的吗 let rec rec algo1 step J if step dSs then J else let a Array init Array2D length1 M fun i gt minby1J i M J le
  • 根据所需长度分割字符串

    有没有一种简单的方法可以根据所需的长度分割字符串 例如 我有一个字符串
  • 如何在主容器中注册类型,但在子容器中解析?

    我有一个统一容器并使用RegisterType使用以下方法注册以下存储库和实现者ContainerControlledLifetimeManager public interface IPersonRepository Person Get
  • 将 C++ string/wchar_t* 转换为 C# 字符串?

    问题 我需要从 C 可执行文件调用 C dll 我使用 COM 它对于 int long 和 bool 工作得很好 但我连一根绳子都拉不起来 IDL 文件说它是一个 BSTR 但我无法正确传递它 也无法检索它 我尝试像使用 VB6 一样使用
  • C++ 中的映射可以接受任何类型的值

    我想在 c 中创建一个可以接受任何类型值的映射 我在 java 中使用 Object 类做了同样的事情 映射但不知道如何在 C 中执行此操作 请帮忙 正如前面的答案正确建议的那样 您不能在 C 中开箱即用 我假设通过 可以接受任何类型的值