Reputation: 173
Is it possible to up-cast a shared pointer object reference in an initializer list?
I have two class hierarchies with matching derived classes. Let's say I have a Base
class which is derived to a Foo
and a Bar
class. Then I have a separate hierarchy with a ProxyBase
class and then (to match the other hierarchy) there's FooProxy
and BarProxy
.
The ProxyBase
class stores a shared_ptr<Base>
. When a ProxyFoo
is created it requires a std::shared_ptr<Foo>&
, when a ProxyBar
is created it requires a std::shared_ptr<Bar>&
.
There are two ways I can make this work:
std::shared_ptr<*>
objects.std::shared_ptr<Base>& obj
as input to the ProxyFoo
and ProxyBar
constructors. This requires a down-cast (which I want to avoid) in the constructor (since I want the Foo
and Bar
specific properties), plus that it makes the contract/API more allowing than it should be.But I'm wondering if this can be done with references.
I think I know what the problem is: When I remove the references it works, and I think that's because "casting" a shared_ptr<X>
is technically not allowed; it can only be "casted" by creating a new shared_ptr
object of a derived/base type. When using references one tries to actually cast one shared_ptr
object to another which isn't allowed. Is this correct?
Originally I thought this was one of those cases where std::static_pointer_cast
would help, but if my hypothesis is correct then that won't help either.
Self-contained example:
#include <memory>
class Base { };
class Foo : public Base
{
private:
int val_;
public:
Foo(int val) : val_(val) { }
};
class ProxyBase
{
protected:
std::shared_ptr<Base> obj_;
ProxyBase(std::shared_ptr<Base>& obj) : obj_(obj) { }
};
class FooProxy : public ProxyBase
{
public:
FooProxy(std::shared_ptr<Foo>& fobj) : ProxyBase(fobj) { }
};
int main()
{
auto f = std::make_shared<Foo>(42);
auto fp = std::make_shared<FooProxy>(f);
}
So my question boils down to: Is it possible to do what I'm trying to do in the (currently non-functional) code above without removing the references and yet keep the Foo
and Bar
specific constructors to FooProxy
and BarProxy
?
Upvotes: 1
Views: 227
Reputation: 303457
A shared_ptr<Derived>
can be converted to a shared_ptr<Base>
, but it is not a shared_ptr<Base>
.
In other words, this compiles:
std::shared_ptr<Derived> pd;
std::shared_ptr<Base> pb = pd;
But this does not:
std::shared_ptr<Base>& pb = pd;
But this does, because const references can bind to temporaries and this will implicitly perform a conversion:
std::shared_ptr<Base> const& pb = pd;
The problem is that you're taking non-const lvalue references in your constructors. You should either take const lvalue references or just take them by value.
Upvotes: 2