我有两个不同的课程如下:
class text
{ };
class element
{ };
我希望将它们存储在class node
:
template <typename T>
class node
{
T cargo;
std::vector<void*> children;
node(T cargo) : cargo(cargo)
{ };
void add_child(T node)
{
this->children.push_back((void*) node);
}
}
所以我会以这种方式调用节点,同时存储text
和element
:
element div;
text msg;
node<element> wrapper(div);
wrapper.add_child(msg);
编辑:要取回我使用T typedef type;
的内容并将空指针转换为(type*)
。
我知道这不是很优雅也不实用,但我无法弄清楚这样做的正确方法是什么。所以请告诉我这是否实际可以接受,如果不是,那么如何以适当的方式做到这一点。
提前致谢!
答案 0 :(得分:6)
#include <vector>
using namespace std;
class Element {};
class Text {};
class Nothing {};
class Node
{
private:
vector< Node* > children_;
protected:
Node() {}
public:
void add( Node* p ) { children_.push_back( p ); }
virtual ~Node() {}
};
template< class Cargo >
class CargoNode
: public Node
{
private:
Cargo cargo_;
public:
CargoNode(): cargo_() {}
};
typedef CargoNode< Element > ElementNode;
typedef CargoNode< Text > TextNode;
typedef CargoNode< Nothing > RootNode;
int main()
{
RootNode* root = new RootNode;
root->add( new ElementNode );
root->add( new ElementNode );
root->add( new TextNode );
root->add( new ElementNode );
// Etc.
}
干杯&amp;第h。,
PS:此示例代码中省略了错误检查,生命周期管理,迭代等。
答案 1 :(得分:5)
我会说void *几乎总是“坏”(对于某些坏的定义)。当然,可能有更好的方式来表达你正在尝试做的事情。如果是我编写这段代码并且我知道我要放入的值的类型,那么我会考虑使用Boost.Variant。如果我没有(例如,这是作为一个库提供给其他人“填满”),那么我会使用Boost.Any
例如:
template <class T, class U>
struct node
{
typedef boost::variant<T, U> child_type;
std::vector<child_type> children;
void add_child(T const &t)
{
children.push_back(t);
}
void add_child(U const &u)
{
children.push_back(u);
}
};
...
node<text, element> n;
n.add_child(text("foo"));
非增强型联合解决方案:
struct node
{
struct child
{
int type; // 0 = text; 1 = element
union
{
text* t;
element* e;
} u;
};
std::vector<child> children;
void add_child(text* t)
{
child ch;
ch.type = 0;
ch.u.t = t;
children.push_back(ch);
}
void add_child(element* e)
{
child ch;
ch.type = 1;
ch.u.e = t;
children.push_back(ch);
}
};
注意:对于使用类型联合的内存管理,你必须更加小心。
答案 2 :(得分:1)
如果你这样做,你怎么能让他们回来?从void*
开始,无法确定地址上实际存储的内容。
编辑:
如果你总是对T*
进行投射,那么你只需将T*
作为参数。
答案 3 :(得分:1)
为element
和text
定义共享基类,然后add_child
可以获取指向基类的指针,向量可以存储指向基类的指针。
答案 4 :(得分:1)
如果您的容器值仅限于少量类型,则可以使用boost::variant
来实现此目的,如下所示:
#include <vector>
#include <boost/variant.hpp>
using namespace std;
class text
{ };
class element
{ };
template <typename T>
class node
{
T cargo;
static std::vector<boost::variant<text, element>> children;
node(const T& cargo) : cargo(cargo)
{ };
void add_child(const T& node)
{
children.push_back(boost::variant<text, element>(node));
}
};
我冒昧地建议其他几个mod--使用const
引用而不是node
构造函数和add_child
上的pass-by-value;使容器children
保持静态,因为我认为每个node<T>
都没有自己的容器是不合理的。在这种情况下,多线程使用add_child
需要锁定。无论您是否可以在最终解决方案中使用Boost,这些注释都适用。
您可以使用vector
或get
对static_visitor
元素执行操作 - 后者更可取,因为您可以使其成为通用元素 - 如图here所示。 vector
迭代的一个示例,类似于您将用于此解决方案的内容:
class times_two_generic
: public boost::static_visitor<>
{
public:
template <typename T>
void operator()( T & operand ) const
{
operand += operand;
cout << operand << endl;
}
};
std::vector< boost::variant<int, std::string> > vec;
vec.push_back( 21 );
vec.push_back( "hello " );
times_two_generic visitor;
std::for_each(
vec.begin(), vec.end()
, boost::apply_visitor(visitor)
);
输出是:
42
你好你好
答案 5 :(得分:0)
首先,使用void指针没有“坏”这样的事情。忘记所有的约定和bla-blas,并做最适合你的情况。
现在,在特定情况下,如果这两个类之间存在任何连接 - 您可以声明一个基类,以便这两个类继承它。然后,您可以声明该基类的指针向量。