Passing Shared_Ptr<Derived> as Shared_Ptr<Base>

Passing shared_ptrDerived as shared_ptrBase

Although Base and Derived are covariant and raw pointers to them will act accordingly, shared_ptr<Base> and shared_ptr<Derived> are not covariant. The dynamic_pointer_cast is the correct and simplest way to handle this problem.

(Edit: static_pointer_cast would be more appropriate because you're casting from derived to base, which is safe and doesn't require runtime checks. See comments below.)

However, if your foo() function doesn't wish to take part in extending the lifetime (or, rather, take part in the shared ownership of the object), then its best to accept a const Base& and dereference the shared_ptr when passing it to foo().

void foo(const Base& base);
[...]
shared_ptr<Derived> spDerived = getDerived();
foo(*spDerived);

As an aside, because shared_ptr types cannot be covariant, the rules of implicit conversions across covariant return types does not apply when returning types of shared_ptr<T>.

shared_ptrBase and objects from derived classes

Yes it is completely fine. Smart pointers are designed to be drop-in replacements for dump pointers.

Of course you have to think about whether to make Base's member functions virtual, just like you would with dumb pointers.

Why isn't shared_ptr to Derived implicitly converted to shared_ptr to Base

The reason for this behavior is the fact that foo is a template. Note, that everything works correctly if foo is not a template:

int foo(std::shared_ptr<Base<int>>) {
return int{};
}

However, when foo is a template, the compiler first needs to instantiate foo, and it wants to be able to instantiate an exact match, since implicit conversions do not apply at this point. And this instantiation can not succeed, thus the error.

One way to workaround this issue would be to make foo a very greedy template, and then add additional constraints of convertibility. For example:

#include <memory>

template <typename T>
class Base {
public:
using Type = T;
};

template <typename T>
class Derived : public Base<T> {
};

template <typename T>
auto foo(T) -> std::enable_if_t<std::is_convertible_v<T, std::shared_ptr<Base<typename T::element_type::Type>>>, typename T::element_type>
{
return typename T::element_type{};
}

int main() {
foo(std::make_shared<Derived<int>>()); //OK
foo(20); // error
}

Note, that I have added a Type member to the base class. This is not strictly necessary, but simplifies the code.

pass derived class shared_ptr as parameter to function that wants base class shared_ptr

Change shared_ptr<A> a; to shared_ptr<B> a;
You can still assign it a pointer of the more derived type, but achieve polymorphism via the base class.

Error passing shared_ptrDerived& as shared_ptrBase& without const

You seem to expect some kind of template covariance, whereby AnyTemplateClass<Derived> can bind to AnyTemplateClass<Base>&. Templates don't work this way. Generally, AnyTemplateClass<Derived> and AnyTemplateClass<Base> are two distinct, completely unrelated classes.

A specific template class may, or course, provide a relationship in some form. shared_ptr<T> in particular has a templated constructor accepting shared_ptr<U> for any U such that U* is convertible to T*.

FooConstRef(d) call works by constructing a temporary - effectively

shared_ptr<TBase> temp(d);
FooConstRef(temp);

But temporaries can't bind to non-const references, that's why FooRef(d) doesn't work in a similar way.

std::shared_ptr upcasting to base class - best method?

As in other use cases of shared_ptr, you should prefer using make_shared instead of constructing the shared_ptr manually:

std::shared_ptr<Base> ptr2 = std::make_shared<Derived>();

This is essentially your version 2, plus the various benefits of make_shared.

Version 1 does a bunch of unnecessary stuff: First you construct a temporary shared_ptr<Derived>, then you dynamic_cast its contents to a base class pointer (while a static_cast would be sufficient here) and then you store that pointer in a different shared_ptr<Base>. So you have a lot of unnecessary runtime operations, but no benefits regarding type safety over Version 2.

Return Base class shared pointer using derived class C++

This should do:

std::shared_ptr<Derived> d = std::make_shared<Derived>();

std::shared_ptr<Base> getBase() { return d; }

How do you convert from shared_ptrderived to shared_ptrbase when returning from a function?

From your error message it appears that you used private or protected inheritance between Vehicle and Boat rather than public.



Related Topics



Leave a reply



Submit