Jump to content
  • Advertisement
Sign in to follow this  
Cygon

Cast vector(Derived *) to vector(Base *)

This topic is 3758 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Actually, my problem is a bit more complicated than the subject gives away. I want to cast a vector< shared_ptr<Derived> > to a vector< shared_ptr<Base> >.
struct InternalManager {
  vector< shared_ptr<XyzConnection> > ActiveConnections;
};

class PublicApi {
  typedef vector< shared_ptr<Connection> > ConnectionVector;
  const ConnectionVector &GetActiveConnections() const {
    return InternalManager::ActiveConnections;
  }
};
I know that technically, I could just reinterpret_cast<> the whole thing, but of course, that's a horrific way to solve my problem. Another solution would be to write my own collection interface:
struct ConnectionList {
  public: virtual size_t size() const = 0;
  public: virtual shared_ptr<Connection> Get(size_t index) = 0;
};
struct XyzConnectionList : public ConnectionList {
  public: virtual size_t size() const { return this->connections->size(); }
  // Darn! Cannot use covariant returns due to shared_ptr<> here!
  public: virtual shared_ptr<Connection> Get(size_t index) {
    return this->connections.at(index);
  }
  public: virtual const shared_ptr<XyzConnection> &GetImpl(size_t index) {
    return this->connections.at(index);
  }
  private: vector< shared_ptr<XyzConnection> > connections;
};
But maybe someone here knows a shorter way that doesn't require me to reimplement a full collection interface with iterators and stuff just to avoid copying a possibly large vector? -Markus-

Share this post


Link to post
Share on other sites
Advertisement
You can't do it, because it's not moral. Casting a vector<Derived*> to a vector<Base*> would imply that a vector<Derived*> IS-A vector<Base*>. But that's not true, because there's something vector<Base*> can do that vector<Derived*> can't: Insert Base*s that aren't Derived*s. Therefore, such a cast could lead to illegal operations.

Now, that's sort of a weak excuse. A const vector<Derived*> is indeed a const vector<Base*>, but you can't do that either. The best you can do is make your function take an iterator pair instead of a container, and template it on the iterator type. Not perfect, but neither's C++.

Share this post


Link to post
Share on other sites
Quote:
Original post by Sneftel
Now, that's sort of a weak excuse. A const vector<Derived*> is indeed a const vector<Base*>, but you can't do that either.


Actually it isn't. For a given Derived object the bit pattern for the Derived * and the Base * for the object aren't necessarily equal.

Share this post


Link to post
Share on other sites
Quote:
Original post by SiCrane
Quote:
Original post by Sneftel
Now, that's sort of a weak excuse. A const vector<Derived*> is indeed a const vector<Base*>, but you can't do that either.


Actually it isn't. For a given Derived object the bit pattern for the Derived * and the Base * for the object aren't necessarily equal.

Yes, I meant IS-A in the parametric polymorphic sense. That is, every operation which is defined on const vector<Base*> is defined on const vector<Derived*> (taking covariance into account, and extending the polymorphism to the const_iterators).

Share this post


Link to post
Share on other sites
Not exactly. The situation with float and double is a little more complicated, because there's no type ordering between them. An operation expecting a double cannot take a float, nor vice versa, without the interposition of a conversion operation which comes up with a new value of the appropriate type. (Admittedly, the fact that this conversion is implicit--something anathema to people who use phrases like "parametric polymorphism"--makes it a difficult area to talk about without ambiguity.)

Share this post


Link to post
Share on other sites
The situation with const vector<Base*> and const vector<Derived*> is the same, because there's no type ordering between them. An operation expecting a const vector<Base*> cannot take a const vector<Derived*>, nor vice versa, without the interposition of a conversion operation which comes up with a new value of the appropriate type.

Share this post


Link to post
Share on other sites
Quote:
Original post by Cygon
Actually, my problem is a bit more complicated than the subject gives away. I want to cast a vector< shared_ptr<Derived> > to a vector< shared_ptr<Base> >.


You can't, and furthermore, you really don't want to. Returning the vector of connections is probably exposing too much anyway. Try offering an iterator interface instead, or just a member function to get the Nth active connection. In the second case, you should be able to convert to a boost::weak_ptr<Connection> fairly easily to hide the information, and in the first it should still be doable (though you'll be entering the somewhat scary world of iterator adaptation). You don't need a full collection interface - just the parts that outside code are interested in. Why should it care that your active connections are stored in a vector, anyway?

Share this post


Link to post
Share on other sites
Quote:
I want to cast a vector< shared_ptr<Derived> > to a vector< shared_ptr<Base> >.
Whilst some people responding may start down the path of figuring out contrived ways of doing such a thing, I'm going to state that you need to take a step back and explain what let you to the situation where you would want to do this.
Chances are that situation can be re-examinined with the conclusion that there is a better way of doing things. Please provide information about the overall goal.

Share this post


Link to post
Share on other sites
Quote:
The situation with const vector<Base*> and const vector<Derived*> is the same, because there's no type ordering between them. An operation expecting a const vector<Base*> cannot take a const vector<Derived*>, nor vice versa, without the interposition of a conversion operation which comes up with a new value of the appropriate type.

Ah, but the nature of the conversion is different. For float/double, the conversion changes the data fundamentally (for a clearer picture, think of float/int). In contrast, the conversion here would be purely representational, twiddling bits to keep the machine happy. Put differently, in a perfect world, there would be two valid ways to type-check this function (though, of course, C++ chooses a particular one), which would nevertheless produce identical results:

template<typename T>
Base* getThird(vector<T> const& v)
{
return v[3];
}

vector<Derived*> v;
getThird(v);

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!