带智能指针的返回类型协方差 C++中我们可以这样做: struct Base { virtual Base* Clone() const { ... } virtual ~Base(){} }; struct Derived : Base { virtual Derived* Clone() const {...} //overrides Base::Clone };
但是,以下操作不会达到相同的效果:带智能指针的返回类型协方差 C++中我们可以这样做: struct Base { virtual Base* Clone() const { ... } virtual ~Base(){} }; struct Derived : Base { virtual Derived* Clone() const {...} //overrides Base::Clone };,c++,smart-pointers,virtual-functions,return-type,C++,Smart Pointers,Virtual Functions,Return Type,但是,以下操作不会达到相同的效果: struct Base { virtual shared_ptr<Base> Clone() const { ... } virtual ~Base(){} }; struct Derived : Base { virtual shared_ptr<Derived> Clone() const {...} //hides Base::Clone }; struct Base { 虚拟共享\u ptr Clone()
struct Base
{
virtual shared_ptr<Base> Clone() const { ... }
virtual ~Base(){}
};
struct Derived : Base
{
virtual shared_ptr<Derived> Clone() const {...} //hides Base::Clone
};
struct Base
{
虚拟共享\u ptr Clone()常量{…}
虚拟~Base(){}
};
派生结构:基
{
虚拟共享\u ptr Clone()常量{…}//隐藏Base::Clone
};
在本例中,Derived::Clone
隐藏而不是重写它,因为标准规定重写成员的返回类型只能从reference(或pointer)更改为Base to reference(或pointer)再更改为Derived。有什么聪明的解决办法吗?当然,有人可能会说,Clone
函数无论如何都应该返回一个普通指针,但现在我们先忘掉它吧——这只是一个示例。我正在寻找一种方法,可以将虚拟函数的返回类型从指向Base
的智能指针更改为指向Derived
的智能指针
提前谢谢
更新:我的第二个示例确实没有编译,多亏了Iammilind我想到了一些想法。首先,如果可以执行第一个版本,只需将该
克隆
保留为隐藏,然后编写另一个受保护的\u克隆
,实际返回派生指针。Clone
都可以使用它
这就引出了一个问题,你为什么要这样做。另一种方式可以是强制(外部)功能,在该功能中,您可以接收共享\u ptr
,如果可能,还可以将其强制为共享\u ptr
。也许是这样的:
template <typename B, typename D>
shared_ptr<D> coerce(shared_ptr<B>& sb) throw (cannot_coerce)
{
// ...
}
模板
共享\u ptr强制(共享\u ptr&sb)抛出(无法强制)
{
// ...
}
您不能直接执行,但有几种方法可以借助非虚拟接口习惯用法来模拟它
对原始指针使用协方差,然后包装它们
struct Base
{
私人:
虚拟基*doClone()常量{…}
公众:
shared_ptr Clone()常量{返回shared_ptr(doClone());}
虚拟~Base(){}
};
派生结构:基
{
私人:
虚拟派生*doClone()常量{…}
公众:
shared_ptr Clone()常量{返回shared_ptr(doClone());}
};
这仅在实际有原始指针开始时有效
通过铸造模拟协方差
struct Base
{
私人:
虚拟共享\u ptr doClone()常量{…}
公众:
共享的_ptr Clone()常量{return doClone();}
虚拟~Base(){}
};
派生结构:基
{
私人:
虚拟共享\u ptr doClone()常量{…}
公众:
共享\u ptr Clone()常量
{return static_pointer_cast(doClone());}
};
在这里,您必须确保Derived::doClone
的所有重写实际上返回指向Derived
或从其派生的类的指针
在本例中,Derived::Clone
隐藏Base::Clone
,而不是覆盖它
不,它不会隐藏它。事实上,这是一个好主意
不能使用仅在返回类型上不同的另一个函数重写或隐藏虚拟函数;因此,返回类型应该相同,否则程序是非法的,因此会出现错误
因此,这意味着没有其他方法可以将
shared_ptr
转换为shared_ptr
。唯一的方法是建立B*
和D*
关系(你在问题中已经排除了这一点)。使用@ymett技术可以改进一个伟大的游戏。这样,您就不必担心忘记在派生函数中添加非虚函数
struct Base
{
private:
virtual Base* doClone() const { ... }
public:
shared_ptr<Base> Clone() const { return shared_ptr<Base>(doClone()); }
virtual ~Base(){}
};
template<class T>
struct CRTP_Base : Base
{
public:
shared_ptr<T> Clone() const { return shared_ptr<T>(doClone()); }
};
struct Derived : public CRTP_Base<Derived>
{
private:
virtual Derived* doClone() const { ... }
};
struct Base
{
私人:
虚拟基*doClone()常量{…}
公众:
shared_ptr Clone()常量{返回shared_ptr(doClone());}
虚拟~Base(){}
};
模板
结构CRTP_基础:基础
{
公众:
shared_ptr Clone()常量{返回shared_ptr(doClone());}
};
派生结构:公共CRTP_基
{
私人:
虚拟派生*doClone()常量{…}
};
@Kerrek可能是因为Clone()
也可能在非多态上下文中调用,在非多态上下文中不希望丢失类型信息。正确的名称是协变返回类型,可能会提高一点。可能的重复为什么C++委员会解决问题,然后再引入另一个麻烦?非常感谢。这很有意义+1这是我推荐的解决方案。(实际上,我一开始就建议不要使用共享ptr
。函数返回共享ptr
很少是好策略。但同样的解决方案也适用于自动ptr
或其他智能指针。)我在这里支持@James Kanze:在界面中使用特定的共享指针会迫使用户选择智能指针。考虑使用不同的味道或智能指针(<代码> UnQuyPPTR <代码>,<代码> AutoPPTR <代码>?)或原始指针,以打开对用户的选择。(unique_ptr
或auto_ptr
的优点是,用户可以获得该指针的所有权并将其传递给不同的智能指针类型,而shared_ptr
用户不能放弃所有权)@James Kanze同意,如果要创建对象,请使用unique_ptr和第一个解决方案。如果已经有了SyrdYPTR(例如,对象是从商店检索的,可能是弱的PTR的——不太可能给出函数名),那么使用第二个解决方案。这仍然是C++需要解决的最大问题之一。在任何地方使用shared_ptr都是非常有用的,但是这样做仍然是一个很大的麻烦。是的,你是对的。这是个错误。很抱歉,问题不正确:)返回类型必须相同的语句错误。C++允许协变指针/引用返回类型(协变意味着当你在一个继承层次中向下移动时,重写的返回类型必须是相同的,或者是在它自己继承层次上的对象),你是指一些东西。
struct Base
{
private:
virtual shared_ptr<Base> doClone() const { ... }
public:
shared_ptr<Base> Clone() const { return doClone(); }
virtual ~Base(){}
};
struct Derived : Base
{
private:
virtual shared_ptr<Base> doClone() const { ... }
public:
shared_ptr<Derived> Clone() const
{ return static_pointer_cast<Derived>(doClone()); }
};
struct Base
{
private:
virtual Base* doClone() const { ... }
public:
shared_ptr<Base> Clone() const { return shared_ptr<Base>(doClone()); }
virtual ~Base(){}
};
template<class T>
struct CRTP_Base : Base
{
public:
shared_ptr<T> Clone() const { return shared_ptr<T>(doClone()); }
};
struct Derived : public CRTP_Base<Derived>
{
private:
virtual Derived* doClone() const { ... }
};