【问题标题】:How to extract derived classes from the base-class container?如何从基类容器中提取派生类?
【发布时间】:2010-12-02 18:13:08
【问题描述】:

使用公共父类将不同类型的对象存储在同一容器中后,我需要将它们提取回来。

[Tests/test0.c++]

int main()
{
    element wrapper;
    wrapper.name = "div";
    wrapper.attributes["id"] = "wrapper";

    cargo<string> text("Learn from yesterday, live for today, hope for tomorrow.");

    wrapper.children.push_back(&text);

    cout << "Name:\t"  << wrapper.name << endl;

         /* I have an explicit cast here,
          * but it can't be used this way
          * since children may have different types
          */
    cout << "Cargo:\t" << ((cargo< string >*) wrapper.children[0])->value << endl;

    return 0;
}

[来源/element.h]

struct element
{
    std::string name;
    std::map< std::string, std::string > attributes;
    std::vector< node* > children;
};

[来源/node.h]

struct node
{ };

[来源/cargo.h]

template <typename Type>
struct cargo
    : public node
{
    Type value;

    cargo(Type value)
        : value(value)
    { }
};

我需要某种类型的持有者来与真实的节点类型相关联,并在更远的转换提取操作中使用它......而不是在我的测试中使用硬编码。

更新:

我正在尝试做的是一个简单的文档对象模型数据结构,以将其用作我的类 xml 语言解析器的符号表条目。我不想使用任何现有的 XML 库,因为它们非常大。我认为 DOM 的想法很简单,因此我可以轻松地将它用于一些更复杂的操作,例如,通过使用 cargo&lt;Type&gt; 允许 DOM 树中的节点的泛型类型。我承认我采用的设计可能不是最合适的!所以我愿意接受建议!

如果有任何帮助,我将不胜感激!

【问题讨论】:

  • 您是否希望在cargo&lt;&gt; 上进行大量操作?
  • 你可能知道节点应该有一个虚拟的dctor。
  • @Nim: cargo 唯一需要的是存储值。不会增加额外的操作。 Type 作为模板参数传递给 cargo 将包含所有业务。
  • 如果您能描述一下您要解决的问题,将会有很大帮助。解决方案可能要容易得多:)
  • 这是我的建议:将问题分成三个部分。一个简单的文档结构、(反)序列化和包含从文档反序列化/序列化的数据的类。请查看 Boost.Serialization 库以获取一些想法。

标签: c++ templates class casting


【解决方案1】:


这个问题可能更多的是关于设计而不是实现。
尽管 Boost.Variant 和 Boost.Any 可以工作,但它们只是一种解决方法。真正的问题可能是从节点类派生的类的可变部分责任没有被封装。
您可以尝试改用合成。一个用于公共接口的主机类和适当数量的组件/委托/任何东西(这些都是从解决方案设计中诞生的:))。

或者...完全不同的解决方案可能适合您。您可能想冒险使用元编程词并放弃通用界面。相反,像元组(类型列表)这样的实体可能会有所帮助。

最好的问候,
马辛

【讨论】:

  • 是的,你是对的!这更多是关于设计而不是实现......我没有用于此目的的相关数据结构和技术(算法、模式、技巧......)的真正经验。我只是想让事情变得清晰和通用,但这会导致我遇到这样的实施问题。我会搜索你提到的解决方案。谢谢! :)
【解决方案2】:

如果您只是流式传输,您可以在基类中实现流操作符,然后委托给派生类中的方法,否则请查看访问者模式。如果不真正了解您可能在 cargo 上进行的操作,很难提出进一步的建议...

【讨论】:

    【解决方案3】:

    如果您不打算在检索时对容器成员进行多态处理,Boost.Variant 可能有助于以确定的方式包装容器成员。

    变体类模板是安全的, 通用的,基于堆栈的可区分的 union 容器,提供一个简单的 操作对象的解决方案 从一组异构类型中 统一的方式。而标准 诸如 std::vector 之类的容器可能是 被认为是“多值、单一 type,”变体是“多类型,单 价值。”

    this prior question 中有一些示例代码。

    【讨论】:

      【解决方案4】:

      如果没有演员阵容,你将无法相处这样的事情。

      但最重要的是,这通常意味着您走错了路。只要您决定cargo 会从node 公开继承,您就提供了两个类之间非常牢固的关系,并且“成为node”比:

      我可以插入容器中 以及其他 node 派生类型

      我们需要知道node 是什么以及可以用它做什么来进一步帮助您。但是,如果您真的需要坚持最初的解决方案,boost.variant 可以帮助您。

      【讨论】:

      • node 类的唯一用途是成为存储在vector 中的容器。我本可以创建单独的类,如 TextNodeElementNode,但我想在内容方面保持通用性......
      【解决方案5】:

      您应该设计使代码不关心基类类型。提供一个对所有人都一样的接口。或者将你需要的纯虚方法添加到基类中并在派生类中实现。

      假设这是不可能的,您尝试过 dynamic_cast 吗?如果转换失败,它会返回 null,而不是像上面的 static_cast 那样抛出。

      希望这会有所帮助, 比兹勒

      【讨论】:

      • 我确实考虑过使用dynamic_cast,但我认为对所要求的目的没有用处。 dynamic_cast 还需要知道 先验 类型。除非我用它来检查非空铸件......(?)
      • 我会把选角作为最后的手段。添加您可以实现的行为或抽象方法,以获取您要转换的功能。
      猜你喜欢
      • 1970-01-01
      • 2012-07-09
      • 1970-01-01
      • 2013-10-15
      • 1970-01-01
      • 2013-01-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多