我有一个FIFO列表数组,我将数据记录添加到
我的数据记录可以是任何标准类型(string,char,int,long,unsigned,float,double),我使用函数将其推送到我的数组。
我想稍后读取数据记录,以便添加它们。
这就是我的尝试:
class List
{
typedef std::pair<typename, std::vector<char>> Record; // typename ??
public:
template <typename T>
void addRecord(T value)
{
char* arr = reinterpred_cast<char*>(&value); // Casting ?
// Convert to Record and push to _records
}
template <typename T>
T getRecord(std::vector<Record>::iterator record) const
{
// Convert Record to T and return
}
private:
std::vector<Record> _records;
}
如何从这些类型转换为字节数组,还是有其他方法可以做到这一点?
示例方法我想使用它:
List list;
list.addRecord("Test string");
list.addRecord(10);
list.addRecord(999999);
list.addRecord("Test string 2");
list.addRecord('X');
...
然后以同样的方式阅读它们:
std::string testString = list.getRecord(...);
char testChar = list.getRecord(...);
int testInt = list.getRecord(...);
....
答案 0 :(得分:3)
由于您只能使用标准库,因此您需要自己实施解决方案或使用现有的易于适应的解决方案。您要查找的内容称为tagged union或变体。这是一个数据结构,其中包含union
以在同一位置保存多种类型的数据,在联合之外的单独值,以指示哪个元素处于活动/使用状态。
对于整数类型,这是完全可以管理的,因为您只需要为设置和检索值提供原始支持。对于更复杂的类型,如std::string
和std::vector
,如果您不使用C ++ 11,事情会变得更加困难。这是因为在C ++ 11之前,union
不能包含具有非平凡复制构造函数,非平凡析构函数或非平凡复制赋值运算符的类型。
评论(here和here)中提供的两个示例any
类似乎都是合理且完整的实现,但需要C ++ 11。两者都只依赖于标准库中的组件,因此它们可能是您可行的解决方案。但是,如果您不使用C ++ 11或需要更简单的解决方案来构建解决方案,我已在下面提供了示例。它处理char
,int
和double
类型,因此如果您需要支持更复杂的类型,则需要添加它们。在复杂类型(并且没有C ++ 11)的情况下,您需要保持指向实例的指针并自己管理生命周期(手动或使用智能指针)。您还需要根据您的特定需求(深拷贝和浅拷贝)处理复制和分配。
简单标记联合:
struct TaggedUnion
{
enum Type
{
Char,
Int,
Double
};
TaggedUnion(const char& value) : type(Char), value(value) {}
TaggedUnion(const int& value) : type(Int), value(value) {}
TaggedUnion(const double& value) : type(Double), value(value) {}
Type getType() const { return type; }
char getChar() const { assert(type == Char); return value.getChar(); }
int getInt() const { assert(type == Int); return value.getInt(); }
double getDouble() const { assert(type == Double); return value.getDouble(); }
private:
union Union
{
Union(const char& value) : charValue(value) {}
Union(const int& value) : intValue(value) {}
Union(const double& value) : doubleValue(value) {}
char getChar() const { return charValue; }
int getInt() const { return intValue; }
double getDouble() const { return doubleValue; }
private:
char charValue;
int intValue;
double doubleValue;
};
Type type;
Union value;
};
使用示例:
#include <iostream>
#include <vector>
#include <cassert>
int main()
{
std::vector<TaggedUnion> values;
values.push_back(TaggedUnion(0.0)); // Store double/float
values.push_back(TaggedUnion(0)); // Store int
values.push_back(TaggedUnion(' ')); // Store char
}
答案 1 :(得分:0)
使用联合,就像另一个答案中建议的那样,是最直接的解决方案。作为替代方案,我想建议一种我认为更加面向对象的方法。我们的想法是为您的值定义一个抽象基类,它定义值所需的所有操作,然后定义每种类型值的派生类:
class Value {
public:
virtual ~Value() {}
// Define operations needed for values, e.g.
virtual void print() = 0;
};
class IntValue: public Value {
public:
IntValue(int val) : m_val(val) {}
virtual void print() {
std::cout << m_val;
}
private:
int m_val;
};
class StringValue: public Value {
public:
StringValue(const std::string& val) : m_val(val) {}
virtual void print() {
std::cout << m_val;
}
private:
std::string m_val;
};
// Equivalent class definitions for other value types.
然后,构建一组值:
std::vector<Value*> values;
values.push_back(new IntValue(42));
values.push_back(new StringValue("Hello"));
要注意的一件事是容器包含指针,并且值是动态分配的。这意味着在销毁容器时不会自动释放这些值。因此,您必须在销毁容器时手动删除元素,或使用某种形式的智能指针而不是裸指针作为存储在容器中的类型。
主要好处是您没有一个类可以处理所有可能的类型。相反,他们很好地孤立。例如,您可以通过简单地实现新类来添加对新类型的支持,而无需更改任何现有代码。