3

我有两个不同的课程,如下所示:

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);
    }
}

所以我会以这种方式调用节点,同时存储textelement

element div;
text msg;

node<element> wrapper(div);

wrapper.add_child(msg);

编辑:要取回我使用的内容T typedef type;并将 void 指针转换为(type*).

我知道这不是很优雅也不是很实用,但我就是不知道这样做的正确方法是什么。所以请告诉我这实际上是否可以接受,如果不是,如何以适当的方式做到这一点。

提前致谢!

4

6 回答 6

7
#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.
}

干杯&hth.,

PS:此示例代码中省略了错误检查、生命周期管理、迭代等。

于 2010-10-21T14:08:34.580 回答
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);
    }
};

注意:您必须更加小心使用类型化联合的内存管理。

于 2010-10-21T12:57:52.983 回答
1

如果你这样做,你将如何让他们回来?从void*没有办法确定地址上实际存储了什么。

编辑:如果您总是进行强制转换T*,那么您可以简单地将T*其作为参数。

于 2010-10-21T12:42:52.273 回答
1

定义一个共享基类elementtext然后add_child可以取一个指向基类的指针,向量可以存储指向基类的指针。

于 2010-10-21T12:43:12.960 回答
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));
    }
};

我冒昧地提出了一些其他的模组——在构造函数上使用const引用而不是按值传递;使容器静态,因为我认为每个人都有自己的容器是没有意义的。在这种情况下,多线程使用需要锁定。无论您是否可以在最终解决方案中使用 Boost,这些评论都适用。nodeadd_childchildrennode<T>add_child

vector您可以使用getor对元素执行操作- 后者更可取,因为您可以将其设为通用 - 如此static_visitor所示。类似于您将用于此解决方案的迭代示例: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

你好你好

于 2010-10-21T13:38:02.357 回答
0

首先,使用 void 指针没有“坏”之类的东西。忘记所有的约定和废话,做最适合你情况的事情。

现在,在您的特定情况下,如果这两个类之间有任何联系 - 您可以声明一个基类,以便这两个类继承它。然后,您可以声明该基类的指针的向量。

于 2010-10-21T12:43:07.607 回答