Testing polymorphism & virtual functions & shared_ptr, I am trying to understand the situation described by the following minimal example.
class B{
public:
// Definition of class B
virtual void someBMethod(){
// Make a burger
};
};
class C : public B {
public:
// Definition of class C
void someBMethod(){
// Make a pizza
};
};
class A{
public:
A(B& SomeB) : Member(std::make_shared<B>(SomeB)){};
std::shared_ptr<B> Member;
};
Now, in the main we can have
int main(){
C SomeC;
A SomeA(SomeC);
A.Member->someBMethod(); // someBMethod from B is being executed.
};
Unless I didn't include some mistake from my actual code to the minimal example, I think SomeC
is getting sliced down to a B
, or at least someBMethod
from B
is being calledin the last line.
Question: What should be the right way to initialize Member
in such a way that the method someBMethod
from C
gets called?
you're performing slicing by calling std::make_shared<B>(SomeB)
This will construct a shared_ptr pointing to a new object of type B
and construct that object by using the copy-constructor on B: B::B(const B& b)
slicing off all information about the C-ness of SomeB
.
change A to:
class A{
public:
A(const std::shared_ptr<B>& pB) : pMember(pB) {}
std::shared_ptr<B> pMember;
};
And main:
int main(){
A SomeA(std::make_shared<C>());
A.pMember->someBMethod(); // someBMethod from C is being executed.
}
I think
SomeC
is getting sliced down to aB
That's exactly what's happening. make_shared
makes a new object of the specified type, forwarding its arguments to a suitable constructor. So this makes a new B
, initialised using its copy-constructor to copy the B
sub-object of SomeC
.
What should be the right way to initialize
Member
in such a way that the methodsomeBMethod
fromC
gets called?
That's tricky: C
is not shared, but Member
is, and you can't have it both ways. It's probably best if you require the user to pass in a shared pointer, exposing the fact that it is to be shared with this class:
A(std::shared_ptr<B> SomeB) : Member(SomeB){}
If you really want to allow it to use a non-shared object, you could create a shared pointer with a dummy deleter, so it doesn't try to share ownership:
A(B& SomeB) : Member(std::shared_ptr<B>(&SomeB, [](B*){})){}
but beware that you are now responsible for ensuring that C
isn't destroyed until after A
, and any copy of it, no longer requires it. You've lost the safety of an "owning" shared pointer.
Whatever you do, don't simply create a shared pointer from &SomeB
. The default deleter will try to delete it, which is an error because it wasn't dynamically created.
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