【问题标题】:std::shared_ptr Class Factory C++std::shared_ptr 类工厂 C++
【发布时间】:2014-11-12 05:51:18
【问题描述】:

我们有一个基类.....

class Node
{
   public:
      std::string Name;
      Node(){};
      ~Node(){};
}

FilterNode 的派生类。 Filter 与节点相同,只是它具有 'filterId' 属性,并且它的构造函数填充 Node.Name='Filter'。

class Filter: public Node
{
   public:
      int filterId;
      Filter() : Node()
      {
         Name="Filter";
      }
}

我有一个 ClassFactory,它在传递字符串时返回 std::shared_ptr<Node>

请通过此链接在 CodeProject 上找到该工厂的代码。

http://www.codeproject.com/Articles/567242/AplusC-b-bplusObjectplusFactory.

代码似乎实例化了一个Filter,但是,返回了一个Node。即对象切片。

std::shared_ptr<Node> n = std::make_shared(Node);  // As expected, doesn't not have filter ID and node.Name is blank.
std::shared_ptr<Filter> f = std::make_shared(Filter);  // As expected, has filterID and node.Name is 'Filter'.

现在我想处理一个 std::shared_ptr(Node) 数组,它可能实际上包含 std::shared_ptr(Filter) ,具体取决于工厂请求的类。

std::shared_ptr<Node> nf = std::make_shared(Filter);     // Error. Does not have filterId, but does have **Node**.Name='Filter'.

我什至尝试了更简单的情况.....并遇到了同样的问题。

Node n = Node();
Filter f = Filter();
Node nf =Filter();   // Error, nf does not have a filterID, but it's Name field is set to 'Filter'.

我在这里做错了什么? Node 是我所有派生类的基类。当我有一个接受 Node 的函数时,我应该能够向它发送一个 Filter 并让 filterId 可用。

在这种情况下,建议使用指针来提供帮助,但是 shared_ptr 会变得很尖。

【问题讨论】:

  • boost 有 shared_dynamic_cast

标签: c++ inheritance c++11 shared-ptr factory-pattern


【解决方案1】:

Node 对派生类可能定义的其他数据成员和函数一无所知。因此,您需要检索shared_ptr&lt;Filter&gt; 才能访问filterId。使用std::dynamic_pointer_cast 执行此操作。

std::shared_ptr<Node> n = ...
auto f = std::dynamic_pointer_cast<Filter>(n);

if(f) {
    // The managed object is a Filter
    std::cout << f->filter_id << '\n';
}

Live demo

如果您知道n 始终包含Filter(或派生自Filter 的内容),则可以改用std::static_pointer_cast

【讨论】:

  • 那么,如果我有一个混合节点和过滤器的向量,我如何跟踪将它们投射到什么?
  • @user2723463 我最初写的是使用static_pointer_cast,但后来我的答案更新为使用dynamic_pointer_cast。后者解决了你的问题。如果您尝试将dynamic_pointer_castNode 转换为Filter,则生成的shared_ptr 将为空。
【解决方案2】:

当您对基类有任何形式的指针或引用时,您只能访问基类 API 公开的内容。如果您想访问filterId,您需要:

  • 将其添加到基本接口(可能使用返回 boost::optional&lt;int&gt; 的函数,或在可用时配对 true,filterId,否则例如 false,0)或

  • 看看能不能把std::dynamic_pointer_cast转为Filter类型,如果返回的指针在布尔上下文中是true,就可以用它来访问filterId

    李>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-25
    相关资源
    最近更新 更多