您的方法基本上朝着正确的方向发展。你将必须知道你输入的类型。您可以使用boost::any,并且您可以将任何内容放入地图中,只要您知道自己放入了什么:
std::map<std::string, boost::any> table;
table["hello"] = 10;
std::cout << boost::any_cast<int>(table["hello"]); // outputs 10
一些答案建议使用boost::variant 来解决这个问题。但它不会让您在地图中存储任意类型的值(如您所愿)。您必须事先知道可能的类型集。鉴于此,您可以更轻松地完成上述操作:
typedef boost::variant<int, std::string, void*> variant_type;
std::map<std::string, variant_type> table;
table["hello"] = 10;
// outputs 10. we don't have to know the type last assigned to the variant
// but the variant keeps track of it internally.
std::cout << table["hello"];
这很有效,因为boost::variant 重载了operator<< 用于此目的。重要的是要了解,如果您想保存当前包含在变体中的内容,您仍然必须知道类型,就像在 boost::any 案例中一样:
typedef boost::variant<int, std::string, void*> variant_type;
std::map<std::string, variant_type> table;
table["hello"] = "bar";
std::string value = boost::get<std::string>(table["hello"]);
变量的赋值顺序是代码控制流的运行时属性,但任何变量使用的类型都是在编译时确定的。所以如果你想从变量中获取值,你必须知道它的类型。另一种方法是使用访问,如变体文档所述。它之所以起作用,是因为该变体存储了一个代码,该代码告诉它最后分配给它的类型。基于此,它在运行时决定它使用哪个访问者的重载。 boost::variant 相当大且不完全符合标准,而boost::any 符合标准但即使对于小类型也使用动态内存(因此速度较慢。变体可以将堆栈用于小类型)。所以你必须权衡你使用的东西。
如果你真的想把对象放入其中,只是它们做某事的方式不同,多态是一个更好的方法。您可以拥有一个派生自的基类:
std::map< std::string, boost::shared_ptr<Base> > table;
table["hello"] = boost::shared_ptr<Base>(new Apple(...));
table["hello"]->print();
这基本上需要这个类布局:
class Base {
public:
virtual ~Base() { }
// derived classes implement this:
virtual void print() = 0;
};
class Apple : public Base {
public:
virtual void print() {
// print us out.
}
};
boost::shared_ptr 是所谓的智能指针。如果您将它们从地图中删除,并且没有其他东西再引用它们,它将自动删除您的对象。理论上,您也可以使用普通指针,但使用智能指针将大大提高安全性。阅读我链接到的 shared_ptr 手册。