我想在C ++中创建一个可以接受任何类型值的映射,我在Java中使用对象类Map进行了相同的操作,但没有获得如何在C ++中执行此操作的方法。请帮忙。
小智 7
正如前面的答案正确建议的那样,您不能在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;
}
Run Code Online (Sandbox Code Playgroud)
可以这样使用:
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;
}
Run Code Online (Sandbox Code Playgroud)
这个输出
Test, 1337
Run Code Online (Sandbox Code Playgroud)
现在有人可能会说这是
Value实例未使用的类型保留了字段)他们是对的。因此,这是使用多态性和模板的替代方法。
第二种方法:
这要求您定义在将值分配给变量时要存储的值的类型,并且需要使用指针。原因如下。
对于这种方法,我们执行以下操作:
创建一个基类ValueBase,该基类用作我们可以作为值类型放入地图中的类。
从此类派生一个Value<T>保存有任意类型的template类型的模板化类T。
为了给std::cout朋友和朋友带来帮助,我们实现了<<for class 的运算符重载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;
}
Run Code Online (Sandbox Code Playgroud)
可以这样使用:
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;
}
Run Code Online (Sandbox Code Playgroud)
或没有智能指针:
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;
}
Run Code Online (Sandbox Code Playgroud)
两者输出
Test, 1337
Run Code Online (Sandbox Code Playgroud)
第二种方法在用法上有几个差异。
首先,您需要使用指针。原因是这样,成员函数vtable得以保留,并且您可以从派生类覆盖基类中的函数。在我们的情况下,这意味着:当我们调用初始化为a output()的类型的指针时,将使用from 函数,而不是from 函数。如果您使用普通变量而不是指针,则将使用from函数,并且我们将从派生类中丢失信息。ValueBaseValue<T>output()Value<T>ValueBaseoutput()ValueBase
其次,这与第一个有关,您需要引用使用该值时获得的指针。如果要输出带有的ValueBase或Value<T>指针std::cout,则需要这样做,std::cout << *var以输出包含的值。如果您只是这样做std::cout << var,则可以正确获取指针的地址。
我确定还有其他选择,尤其是在使用Boost时,但是我对此并不熟练。其他人可能对此有更多有价值的信息。
除此之外,您正在做的事情听起来像是懒惰。C ++具有强类型系统是有原因的。它不仅定义明确,而且您还知道对代码的期望。如果您开始使事情变得模糊,并使用任意容器对象执行各种任务,那么您的代码将失去可读性,清晰度,并且(很可能)会产生大量难以跟踪,调试和最终修复的错误,因为您需要支持您介绍的所有精美容器,以保持框架运行。
如果要使用Java之类的语言,最好使用Java而不是C ++。
| 归档时间: |
|
| 查看次数: |
4598 次 |
| 最近记录: |