虚拟函数未返回具有多级继承的派生类型

Virtual function not returning derived type with multi-level inheritance

本文关键字:继承 派生 类型 多级 函数 返回 虚拟      更新时间:2023-10-16

我有一个具有多个继承级别的类层次结构。

  1. cloneable声明了一个返回cloneable *的纯虚拟成员函数
  2. base派生自cloneable,但不声明任何成员函数
  3. 最后,derivedbase派生并定义了虚拟函数,但将返回类型重写为derived *

通过指向derived对象的base指针调用虚拟函数将返回cloneable *。我期望base *,因为虚拟函数的实现返回可转换为base *derived *。这是怎么回事?

如果我在base中声明纯虚拟函数,我最终可以从中获得base *,但我不明白为什么这个声明是必要的。

代码:

struct cloneable
{
virtual cloneable * clone() = 0;
};
struct base : cloneable 
{
// virtual base * clone() = 0;    // this line resolves the compile error
};
struct derived : base
{
virtual derived * clone () { return new derived; }
};
int main(int, char**)
{
derived d;
base * bp = &d;
base * bbp = bp->clone();  // error: invalid conversion 
// from ‘cloneable*’ to ‘base*’      
return 0;  
}

注意:为了缩短代码示例,我特意省略了虚拟析构函数。

您认为编译器应该如何猜测您想要一个返回base*的版本,而不需要任何声明?


虽然上面的问题回答了你的直接问题,但我觉得我也应该补充一些建议。

首先,

  • 确实使clone函数成为const,以便可以在const对象上或通过右值表达式调用它

virtual cloneable* clone() const;

其次,要创建对象的克隆

  • 返回new T( *this )(使用复制构造函数),而不是new T(使用默认构造函数)

第三,

  • 为了安全起见,对于公开可用的clone操作,返回智能指针(如unique_ptr<MyClass>),而不是原始指针

然而,随着返回类型变为智能指针,您将不再直接受益于C++对协变函数结果的支持,这仅适用于原始指针和引用。因此,一种方法是使用一个非public的原始指针结果实现,它可以具有协变的结果类型,以及一个返回智能指针的类型化public包装器。实际上,您正在为公共接口自己实现协方差,它可以看起来像这样:

#include <memory>       // std::unique_ptr
using namespace std;
class Base
{
private:
virtual Base* virtualClone() const
{
return new Base( *this );
}
public:
unique_ptr< Base > clone() const
{
return unique_ptr< Base >( virtualClone() );
}
};
class Derived
: public Base
{
private:
virtual Derived* virtualClone() const
{
return new Derived( *this );
}
public:
unique_ptr< Derived > clone() const
{
return unique_ptr< Derived >( virtualClone() );
}
};
int main()
{
Derived d;
Base* bp = &d;
unique_ptr< Base > bbp = bp->clone();
}