0
votes

We have a base class.....

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

Filter is a derived class of Node. Filter is the same a node, except it has a 'filterId' property and it's constructor populates Node.Name='Filter'.

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

I have a ClassFactory that returns std::shared_ptr<Node> when passed a string

Please find the code to that factory on CodeProject following this link.

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

The code seems to instantiate a Filter, but, returns a Node. i.e. Object slicing.

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'.

Now i want to handle an array of std::shared_ptr(Node) which may actually contain std::shared_ptr(Filter) depending on what the class is requested from the factory.

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

I even tried the simpler case..... and got the same problem.

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'.

What am i doing wrong here? The Node is a base class for all of my derived classes. When i have a function that accepts a Node, i should be able to send it a Filter and have the filterId available.

Pointers are advised to help in situations like this, however the shared_ptr is a pointy as things will get.

2
boost have shared_dynamic_cast - thomas

2 Answers

1
votes

Node doesn't have any knowledge of additional data members and functions that derived classes may define. So you need to retrieve a shared_ptr<Filter> to be able to access filterId. Use std::dynamic_pointer_cast to do this.

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

And if you know that n always contains a Filter (or something derived from Filter), you can use std::static_pointer_cast instead.

0
votes

When you have any manner of pointer or reference to the base class, you can only access the things that the base class API exposes. If you want to access filterId, you need to either:

  • add it to the base interface (perhaps with a function that returns a boost::optional<int>, or pair true,filterId when available, otherwise e.g. false,0) or

  • see if you can std::dynamic_pointer_cast to the Filter type, if the returned pointer is true in a boolean context, you can use it to access the filterId.