测试多态性&虚拟功能& shared_ptr,我试图理解以下最小例子描述的情况。
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;
};
现在,主要是我们可以
int main(){
C SomeC;
A SomeA(SomeC);
A.Member->someBMethod(); // someBMethod from B is being executed.
};
除非我没有从实际代码到最小示例中包含一些错误,否则我认为SomeC
会从B
切割为someBMethod
,或者至少从B
Member
被称为最后一行。
问题:以someBMethod
中的C
方法调用方式初始化{{1}}的正确方法是什么?
答案 0 :(得分:6)
您通过调用std::make_shared<B>(SomeB)
来执行slicing这将构建一个指向类型为B
的 new 对象的shared_ptr,并通过以下方式构造该对象使用B上的复制构造函数:B::B(const B& b)
切除有关SomeB
的C-ness的所有信息。
将A更改为:
class A{
public:
A(const std::shared_ptr<B>& pB) : pMember(pB) {}
std::shared_ptr<B> pMember;
};
主要:
int main(){
A SomeA(std::make_shared<C>());
A.pMember->someBMethod(); // someBMethod from C is being executed.
}
答案 1 :(得分:3)
我认为
SomeC
正逐渐变为B
这正是发生了什么。 make_shared
创建一个指定类型的新对象,将其参数转发给合适的构造函数。因此,这会生成一个新的B
,使用其复制构造函数进行初始化,以复制B
的{{1}}子对象。
以
SomeC
中的方法Member
被调用的方式初始化someBMethod
的正确方法是什么?
这很棘手:C
未被分享,但是C
是,并且你无法双管齐下。如果您要求用户传入共享指针,那么它可能是最好的,这表明它将与此类共享:
Member
如果你真的想让它使用非共享对象,你可以创建一个带有虚拟删除器的共享指针,因此它不会尝试共享所有权:
A(std::shared_ptr<B> SomeB) : Member(SomeB){}
但请注意,您现在有责任确保在A(B& SomeB) : Member(std::shared_ptr<B>(&SomeB, [](B*){})){}
之后C
不被销毁,并且其任何副本不再需要它。你已经失去了拥有&#34;拥有&#34;共享指针。
无论你做什么,都不要简单地从A
创建共享指针。默认删除器将尝试删除它,这是一个错误,因为它没有动态创建。