我有一个问题与从类返回共享指针有关。 我班的一部分看起来像这样:
typedef std::shared_ptr<IBaseInterface> IBaseInterfaceSP;
...
IBaseInterfaceSP getMyInterface()
{
m_spBase = std::make_shared<IBaseInterfaceSP>( m_derivedInterface);
return m_spBase;
}
其中m_derivedInterface
和m_spBase
都是我班的私人成员,即:
private:
IBaseInterfaceSP m_spBase ;
DerivedInterface m_derivedInterface;
此外,DerivedInterface
继承自IBaseInterfaceSP
。
getInterface
是我班的公共职能。
这是从类中返回指针的正确方法吗?切片或类似的东西会有问题吗?
P.S。如果有一些不清楚的地方,我很抱歉(不允许我在此处公开所有代码,仅发布某些部分),如果是这样,请告诉我。
答案 0 :(得分:4)
我看到这段代码有几个问题。
1。延迟初始化
每次调用getInterface时,都会创建IBaseInterface类的新实例。作为您班级的用户,我不会从名为“ get”的方法获得这种行为。
我猜您想实现延迟初始化,在这种情况下,您可以这样做:
IBaseInterfaceSP getInterface()
{
if (!m_spBase)
{
m_spBase= std::make_shared<IBaseInterface>( m_derivedInterface );
}
return m_spBase;
}
2。命名约定
您正在实例化一个名为IBaseInterface的类,这听起来像一个抽象类(“ I”前缀在历史上一直用于接口)。您可能应该重命名您的类,以使其听起来不抽象。另外,“ I”前缀在“ Interface”后缀中是多余的。
但是,在我认为“好的” OOP中,用户不需要知道您正在向他们提供接口。因此,不需要将具体名称与抽象类区分开的命名约定。
3。所有权语义
共享指针用于共享所有权:返回共享指针时,您是在告诉类的用户他们也将拥有返回的对象。通常,不需要。在大多数情况下,您会返回一个非所有者指针,也就是原始指针。例如:
IBaseInterface* getInterface()
{
return m_spBase.get(); // Instantiation done elsewhere, for example in constructor
}
4。切片
这里确实有切片发生。这行:
m_spBase = std::make_shared<IBaseInterface>( m_derivedInterface );
实际上扩展为包含与此等效的代码:
auto newInstance = new IBaseInterface(m_derivedInterface );
依次,上面的行将调用IBaseInterface类的副本构造函数,其签名类似于:
IBaseInterface(IBaseInterface& other)
因此,在该调用的上下文中,m_derivedInterface被解释为IBaseInterface引用。因此,在调用“ new”期间,仅IBaseInterface的成员将被复制,从而丢失存储在派生类DerivedInterface中的所有信息。
所有这些,在我看来,您真正想要的是直接访问m_derivedInterface对象。您现在正在做的是,将实例复制到另一个对象中并返回新对象。我认为您真正想要的是:
IBaseInterface* getInterface()
{
return &m_derivedInterface;
}
如果您坚持使用共享所有权,只需存储指向m_derivedInterface的共享指针而不是值:
MyClass(Args args)
{
m_derivedInterface.reset(new DerivedInterface(args));
}
std::shared_ptr<IBaseInterface> getInterface()
{
return m_derivedInterface;
}
std::shared_ptr<IBaseInterface> m_derivedInterface;