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
How to Make My Split Work Only on One Real Line and Be Capable to Skip Quoted Parts of String
Double Delete in Initializer_List VS 2013
What Are Your Favorite C++ Coding Style Idioms
Which Stl Container Should I Use for a Fifo
Garbage Collection in C++ -- Why
How to Deal with "Signed/Unsigned Mismatch" Warnings (C4018)
Calling Functions in a Dll from C++
With a Private Modifier, Why Can the Member in Other Objects Be Accessed Directly
Best Introduction to C++ Template Metaprogramming
Returning a Const Reference to an Object Instead of a Copy
How to Force Cache Coherency on a Multicore X86 Cpu
Why Is 'Std::Initializer_List' Often Passed by Value
How Is Static Variable Initialization Implemented by the Compiler