C++中与Java Map<String, Object>等效的内容是什么?

6

在Java中,您可以创建一个将字符串映射到通用对象类型的Map,这些对象类型可以明确地转换为其他类。在C++中是否有模拟此功能的好方法?


在C++11/14中有一个叫做std::map的映射表,请检查它是否符合您的要求。 - tibetty
以及 std::unordered_map - phuclv
1
我认为OP在谈论一个可以接受任何类型对象的类Object,而不是数据容器集合Map。 - ΦXocę 웃 Пepeúpa ツ
2
你可能正在寻找std::any。或者只是一个普通的void*。如果不知道你计划如何使用这个东西,很难说。 - Igor Tandetnik
2
这实际上比一开始看起来的问题要开放得多。C ++中没有直接对应Java Map <String,Object>,因为C ++类型系统本身在根本上有太大的区别。例如,Map <String,Object> 是一个java泛型,基本上是具有语法糖的Map <Object,Object> 并且是一个基类。C ++中的std :: map <std :: string,Foo>是一个一级对象,它确实具有std :: string键。此外,在C ++中没有等价于“Object”的东西,尽管有弱类型/包装器。 - H Walters
1
如果在Java中使用Map<String,Object>时有一个特定的问题需要解决,那么在C++中也很可能有至少一种特定的方法来解决这个问题;然而,通常情况下,我能够想到至少5种不同的方法来“模拟”它们(并且它们都是不同的)。 - H Walters
2个回答

3
在C++17中,您可以使用std::map<std::string, std::any>

1
作为一种强类型语言,C++没有"通用对象类型"。它确实有关联容器:std::map(一种二叉树的变体)和std::unordered_map(一种哈希表的变体)。哪个更好取决于使用情况,并且通常需要进行分析才能决定。
我能想到的最接近通用对象的东西是所有可能放入此映射中的对象的共同祖先。这里的想法是创建一个具有动态多态性的类层次结构,并将对象存储在作为该共同祖先转换的指针的映射中。 理想的设计将使这些对象回转到其派生类不必要。如果需要这样的转换,就必须使用dynamic_cast(并可能检查它是否成功)。

为了保持多态性,必须存储指向地图中对象的指针,而不是对象本身。否则,尝试插入地图中的对象只会存储共同祖先部分,并且多态性将会丢失。还需要决定地图是否拥有这些对象(没有垃圾回收)。如果没有,简单的指针可以工作。如果地图拥有这些对象,建议使用“唯一指针”(std::unique_ptr)来存储它们。

#include <unordered_map>
#include <string>
#include <memory> // std::unique_ptr<>, std::make_unique()
#include <iostream>

class NotSoGenericClass {
    public:
  virtual ~NotSoGenericClass() = default;
  virtual std::string name() const
    { return "NotTooGenericClass()"; }
};

class EvenLessGenericClass: public NotSoGenericClass {
  int fValue = 0;
    public:
  EvenLessGenericClass(int value): fValue(value) {}
  virtual std::string name() const override
    { return "EvenLessGenericClass(" + std::to_string(fValue) + ")"; }
  int value() const { return fValue; }
};

int main() {
  //
  // map holding (and owning) "not so generic objects"
  //
  std::unordered_map<std::string, std::unique_ptr<NotSoGenericClass>> allObjects;

  //
  // populate it
  //
  allObjects["any"] = std::make_unique<NotSoGenericClass>();
  allObjects["six"] = std::make_unique<EvenLessGenericClass>(6);
  allObjects["one"] = std::make_unique<EvenLessGenericClass>(1);

  std::cout << "Object 'six' says: " << allObjects["six"]->name() << std::endl;

  std::cout << "Now dumping all " << allObjects.size() << " objects:";
  for (auto const& keyAndObject: allObjects) {

    auto const& key = keyAndObject.first;
    auto const* object = keyAndObject.second.get();

    //
    // base class interface is always available:
    //
    std::cout << "\n[" << key << "] " << object->name();

    //
    // object-specific one requires a cast:
    //
    auto const* lessGen = dynamic_cast<EvenLessGenericClass const*>(object);
    if (lessGen) std::cout << " (value is " << lessGen->value() << ")";

  } // for
  std::cout << std::endl;

  return 0;
} // main()

在我的平台上,这段代码(使用C++14)会输出:
[one] EvenLessGenericClass(1) (value is 1)
[six] EvenLessGenericClass(6) (value is 6)
[any] NotTooGenericClass()

(同时说明了地图名称中“unordered”的含义)。此示例是使用g++ -Wall -pedantic -std=c++14 -o test.exe test.cpp(GCC 6.4.0)编译的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接