2

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

  1. cloneable声明一个纯虚成员函数返回cloneable *.
  2. base派生自cloneable,但不声明任何成员函数。
  3. 最后,从虚函数derived派生base并定义,但将返回类型覆盖为derived *.

通过base指向derived对象的指针调用虚函数返回cloneable *。我期待base *,因为虚函数的实现返回derived *可转换为base *. 这里发生了什么?

如果我在 中声明纯虚函数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;  
}

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

4

1 回答 1

4

你认为编译器应该如何猜测你想要一个返回 a 的版本base*,没有任何声明?


虽然上述问题回答了您的直接问题,但我觉得我还应该添加一些建议。

首先,

  • 做这个clone函数const,以便可以在const对象上或通过右值表达式调用它。

IE,

virtual cloneable* clone() const;

其次,要创建对象的克隆

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

第三,

  • 为了安全起见,对于公开可用的clone操作,返回一个智能指针,例如 a 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();
}
于 2012-09-17T04:01:04.463 回答