所以我试图创建一个"表" C ++中的类,结构如下:
Table.h
class Table
{
private:
class TableImpl;
TableImpl* impl;
};
Table.cpp
class Table::TableImpl
{
private:
class Row
{
private:
template <typename T>
class RowDataCell
{
T data;
}
std::vector<RowDataCell*> data;
};
std::vector<Row*> rows;
};
TableImpl
由std::vector
个Row
个对象组成,每个Row
个对象由std::vector
个通用RowDataCell
个对象组成。唯一的问题是,我无法创建std::vector
,因为我需要为RowDataCell*
提供一个模板参数,这将阻碍我有一个容器杂项对象的目标。
使用标准C ++是否有办法实现这一目标。
答案 0 :(得分:4)
有两种合理的方法。
第一个是区别性联盟,另一个是旧C风格void*
&#34的类型安全变体;任何东西都可以在这里&#34;。
我首先提到它们的两个boost
实现:
boost::variant<A,B,C>
(和传入的std::experimental::variant
)是一个有区别的联盟。它可以存储A
,B
或C
类型的内容。有各种类型安全的方法来获取元素,或通过&#34;访问&#34;对它们执行操作。 Variant对它可以容纳的类型有一些限制,并且取决于你如何注入这些类型的更多限制。
boost::any
(和传入的std::experimental::any
)是一个具有值语义的类型安全的void*
。几乎任何东西都可以存储在其中(any
要求你的对象是CopyConstructable),但只有你知道存储在其中的东西的确切类型并且要求它才能访问它。
自己编写任何一个都是可行的,但我建议使用它们,或者至少理解它们并克隆其界面和模式的大部分内容。
variant
可以存储实例&#34;内部&#34;在其内部,通常是一种更好的方法。您可以使用union
,类型列表和该列表的索引来模拟它,以及一堆元编程样板。另外,对齐问题很棘手。
any
更容易编写,但仍然有点挑战。它是一个非常基本的类型擦除对象,只有&#34;强制转换为X&#34; (通过typeid
或同等学历)并复制公开。如果你曾经看到std::function
被实施,你就到了一半。
答案 1 :(得分:0)
是的,有一种标准的C ++方式来实现记录表,它可能会变得丑陋。我试过了。
我们假设一个表是记录的容器 记录可以包含字段或记录 字段可以是不同的类型,例如整数,字符串和BLOB。
至少在我看来,目标是尽可能保持事物的通用性,直到最低级别,即专业领域。这意味着字段值通过字符串传递。
所以,这是一个简化的模型:
struct Component; // The base of everything.
struct Record : public Component {
std::vector<Component *> components;
};
struct Field : public Component {
std::string name;
virtual std::string get_value_as_string(void) = 0;
};
struct Field_String : public Field;
//... And so on.
struct Table {
std::vector<Record *> rows;
};
基本问题是表格的每个单元格都可能具有不同的类型。该表可以有无限的列和行。
我还建议阅读有关数据库的内容。许多数据库接口都可以解决表的问题。
答案 2 :(得分:0)
有几种方法可以做你想要的。一种方法是为要放入容器的类型定义一个公共接口,然后将指向该接口的指针放入向量中:
class RowDataCellInterface
{
public:
virtual ~RowDataInterface() {}
virtual std::string toString() const = 0;
virtual std::unique_ptr<RowDataInterface> clone() const = 0;
};
然后,您甚至可以以模板化的方式派生此接口的实现:
template <typename T>
class RowDataCell final : public RowDataCellInterface
{
public:
virtual std::string toString() const
{
std::stringstream ss;
ss << data;
return ss.str();
}
virtual std::unique_ptr<RowDataInterface> clone() const
{
std::make_unique<RowDataCell>(*this);
}
private:
T data;
};
现在可以把这些东西放到这样的矢量中:
std::vector<std::unique_ptr<RowDataCellInterface>>
一切都应该正常。要复制矢量,您应该使用界面的clone()
成员函数。有几种图书馆解决方案可以帮助您实现您想要的目标。其中一个是boost::variant
,我建议。我对一个非常相似的问题here做了非常详细的回答。另一个库解决方案是boost::any
,一开始可能看起来更简单,但是为了用它做一些有意义的事情,你必须知道所包含事物的类型,它在访问时被删除。我希望大多数情况下boost::variant
超过boost::any
。