Reputation: 279
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?
Upvotes: 7
Views: 5456
Reputation: 254431
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.
Upvotes: 3
Reputation: 4283
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.
}
Upvotes: 8