• 12
• 12
• 9
• 10
• 13

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

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

## 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 on other sites
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 on other sites
Quote:
 Original post by SneftelNow, that's sort of a weak excuse. A const vector is indeed a const vector, 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 on other sites
Quote:
Original post by SiCrane
Quote:
 Original post by SneftelNow, that's sort of a weak excuse. A const vector is indeed a const vector, 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 on other sites
That's like arguing a float IS-A double.

##### 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 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 on other sites
Quote:
 Original post by CygonActually, my problem is a bit more complicated than the subject gives away. I want to cast a vector< shared_ptr > to a vector< shared_ptr >.

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 on other sites
Quote:
 I want to cast a vector< shared_ptr > to a vector< shared_ptr >.
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 on other sites
Quote:
 The situation with const vector and const vector is the same, because there's no type ordering between them. An operation expecting a const vector cannot take a const vector, 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);