【问题标题】:How to clone multiple inheritance object?如何克隆多继承对象?
【发布时间】:2011-04-26 00:51:54
【问题描述】:

我已经定义了一个 Cloneable 接口:

struct Cloneable
{
  virtual Cloneable * clone(void) const = 0;
}

我还有一些其他的接口类(内容与问题无关):

struct Interface
{
};

struct Useful_Goodies
{
};

我创建了一个继承自上述类的叶对象:

struct Leaf : public Cloneable, public Interface, public Useful_Goodies
{
  Leaf * clone(void) const  // Line #1 for discussion.
  {
     return new Leaf(*this);
  }
};

我收到了错误:

overriding virtual function return type differs and is not covariant from 'Cloneable::clone'

如果我将类型更改为Cloneable *,我会收到以下错误消息:

'return' : ambiguous conversions from 'Leaf *' to 'Cloneable *'

我的问题(所有相关):

  1. 叶类如何解决 Cloneable的要求 界面?
  2. 是否有更好的解决方案来实施 克隆合约,其中所有对象 保证实现克隆?

我将此范例用作通用编程(记录、字段和数据库)的一部分。

编译器:MS Visual Studio 2008;平台:Windows XP 和 Vista

【问题讨论】:

  • 我使用了相同的编译器,一切编译正常。这是一个错误,已从 VC6 开始解决。
  • 有些事情你没有告诉我们,因为这段代码在 VS 2008 中对我来说编译得很好。
  • 真正的问题是为什么需要克隆一个对象。我从 Java 转换中看到了很多(这是一个大问题/概念),但我还没有看到 C++ 代码的需求。对你实际想要达到的目标的解释可能会给你一些关于 c++ 技术的好建议,
  • @Martin York:我发现这在创建动态语言工具(如解释器)时尤其常见,以满足对可以动态调用的复制构造函数的需求。我还没有找到它的任何其他有效用途,但这并不意味着它不存在。我更愿意让人们从怀疑中受益,尽管它可能总是会进行干预。

标签: c++ clone multiple-inheritance generic-programming cloneable


【解决方案1】:

让您的 clone 函数返回 Cloneable * 是正确的。

如果您的接口之一也派生自 Cloneable,您将获得模棱两可的转换。

编辑: Alf 在 cmets 中指出,Leaf::clone 不仅可以返回 Leaf*,而且实际上更可取。我的立场是正确的。

【讨论】:

  • 我发现其中一个接口也继承自 Cloneable 作为虚拟接口。 “主”继承线继承自 Cloneable 但不是虚拟的。
  • 是的,但返回 Leaf* 也是正确的,而且更实用。返回 Cloneable* 是一种 Java 主义。在 C++ 中,应该使用最具体的可用类型进行静态类型检查。 OP的问题显然是/显然在他没有提供的信息中。即使用过时的预标准编译器(或其他可能的东西)。干杯&hth.,
  • @Alf,我一定不同意。该函数被定义为在基类中返回Cloneable*,因此它必须返回。当然你会想要创建一个Leaf* 来返回,但它必须在返回之前转换为正确的类型,尤其是在涉及多重继承时。如果调用者已经知道返回的是哪种类,它可以使用复制构造函数并完全避免 clone 方法以进行高级类型检查。
  • 不,这是不正确的。这是一种新手级别,所以我将您发送到常见问题解答而不是引用标准。请参阅常见问题解答项目"20.8 What is a "virtual constructor"?""中对 C++“协变”函数结果的解释。嗯,虽然我正在抛出链接,但我不妨参考我自己在 how to implement cloning in a reusable way 上的博客条目。:-) Cheers & hth.,
  • @Alf:令人惊讶的是,C++ 语言中还有一些让我看起来像个无知的傻瓜的地方。感谢您的链接。
【解决方案2】:

您可能没有提到Interface 或其他一些基类也继承了Cloneable。 “模糊转换”意味着Leaf 可能包含多个Cloneable 基类子对象。 (协变返回类型的问题可能是同一问题的直接结果。)

您需要使用virtual inheritance 来解决这个问题(推荐和链接阅读:C++ FAQ Lite 主题 25.8 到 25.13)。首先,将: public Cloneable所有 个实例更改为: public virtual Cloneable

【讨论】:

    【解决方案3】:

    我可以冒险说你可能不是从多个路径继承Cloneable。也就是说,除了直接Cloneable 之外,您的其他一些基础(直接或间接)继承自Cloneable。这使得从Leaf*Cloneable* 的转换不明确,因为Leaf 中有多个Cloneable 基数。

    简单的解决方案是使用接口的虚拟继承:

    struct Cloneable {
       virtual Cloneable * clone() = 0;
    };
    struct Interface : virtual Cloneable {
    };
    struct Test : virtual Cloneable, Interface {
       virtual Test* clone() {
          return new Test(*this);
       }
    };
    

    虚拟继承意味着即使InterfaceTest 都继承自Cloneable,也只有一个Cloneable 基础对象。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-15
      • 1970-01-01
      • 2018-11-24
      • 1970-01-01
      • 2010-11-08
      • 2012-11-17
      相关资源
      最近更新 更多