class Interface
{
};
class Class : public Interface
{
};
class Foo
{
public:
std::vector<std::shared_ptr<Interface>>& GetInterfaces()
{
return *(std::vector<std::shared_ptr<Interface>>*)(&m_data);
//return m_data;
}
private:
std::vector<std::shared_ptr<Class>> m_data;
};
This works but is ugly and scary. Is there a better/safer way to do it? I don't want to make m_data
of type std::vector<std::shared_ptr<Interface>>
because the module Foo
belongs to works entirely with Class
's, Interface
(and Foo::GetInterfaces()
) are implemented to interact with a separate module that should only know about the Interface
functionality.
Let me know if anything here is unclear, it makes sense to me but I've been banging my head against the problem for a while.
Casting is not correct, they are distinct types; I am pretty certain you are invoking undefined behaviour.
You need to construct a new vector and return it by value.
std::vector<std::shared_ptr<Interface>> b (m_data.begin(), m_data.end());
return b;
This should still be fairly cheap (1 allocation).
Besides that this is not possible with the implementation of vector
, the issue is also that references don't convert. Your code is even worse and is undefined behavior.
What you can do is provide an interface that exposes a range or begin/end
instead of the container itself. If you combine that with a transform_iterator
that does the conversion, you should be set.
Sample code:
class Interface {
virtual ~Interface();
};
class X : public Interface {};
class C {
private:
typedef std::shared_ptr<Interface> iptr_type;
typedef std::shared_ptr<Class> ptr_type;
std::vector<ptr_type> v_;
struct F {
iptr_type
operator()(ptr_type p) { return iptr_type(p); }
};
typedef boost::transform_iterator<
F, std::vector<ptr_type>::iterator> iiterator;
public:
iiterator
begin()
{
return boost::make_transform_iterator(
begin(v_), F());
}
iiterator
end()
{
return boost::make_transform_iterator(
end(v_), F());
}
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With