代码之家  ›  专栏  ›  技术社区  ›  mmocny

来自两个派生类的多重继承

  •  26
  • mmocny  · 技术社区  · 16 年前

    我有一个作为接口的抽象基类。

    我有两个派生类的“集合”,它们实现了抽象类的一半。(一个“set”定义与初始化相关的抽象虚拟方法,另一个“set”定义与实际“work”相关的方法。)

    然后,我有派生类,它们使用多重继承来构造完全定义的类(并且本身不添加任何内容)。

    所以:(错误的伪代码)

    class AbsBase {
      virtual void init() = 0;
      virtual void work() = 0;
    }
    
    class AbsInit : public AbsBase {
      void init() { do_this(); }
      // work() still abs
    }
    
    class AbsWork : public AbsBase {
      void work() { do_this(); }
      // init() still abs
    }
    
    class NotAbsTotal : public AbsInit, public AbsWork {
      // Nothing, both should be defined
    }
    

    首先,我能做这个吗?我可以从两个类继承吗?这两个类都是从同一个基派生的?(我希望如此)。

    这里是“真正的问题”,不过(为了简化示例,我在上面撒了一点谎)。

    我真正做的是向基类添加非抽象访问器方法:

    class AbsBase {
    public:
      void init() { init_impl(); }
      void work() { work_impl(); }
    
    private:
      virtual void init_impl() = 0;
      virtual void work_impl() = 0;
    }
    

    因为,一个常见的习惯用法是使所有虚拟方法私有化。

    不幸的是,现在absinit和abswork都继承了这些方法,因此notabstotal继承了“每个方法中的两个”(我意识到我可能会扼杀编译时实际发生的事情)。

    无论如何,G++抱怨在尝试使用类时:“请求member init()是不明确的”。

    我假设,如果我使用absbase类作为纯接口,那么就可以避免这种情况(假设上面的示例是有效的)。

    所以: -我的实现还差得远吗? -这是使虚拟方法私有化的习惯用法的限制吗? -如何重构我的代码以实现我想要的?(提供一个公共接口,但允许将实现替换为成员函数的“集合”)。

    编辑:

    似乎我不是第一个: http://en.wikipedia.org/wiki/Diamond_problem

    虚拟继承似乎是这里的解决方案。我以前听说过虚拟继承,但我还没有完全理解它。我仍然乐于接受建议。

    5 回复  |  直到 11 年前
        1
  •  35
  •   comingstorm    16 年前

    看起来您想进行虚拟继承。这是否真的是个好主意是另一个问题,但下面是你如何做到的:

    
    class AbsBase {...};
    class AbsInit: public virtual AbsBase {...};
    class AbsWork: public virtual AbsBase {...};
    class NotAbsTotal: public AbsInit, public AbsWork {...};
    

    基本上,默认的非虚拟多重继承将包括 每个基类 在派生类中,并包含其所有方法。这就是为什么你有两个ABSBASE副本——并且你的方法使用不明确的原因是加载了两组方法,所以C++没有办法知道要访问哪一个副本!

    虚拟继承将对虚拟基类的所有引用压缩为一个数据结构。这将使基类中的方法再次明确。但是,注意:如果两个中间类中有额外的数据,那么可能会有一些额外的运行时开销,以使代码能够找到共享的虚拟基类。

        2
  •  1
  •   Martin v. Löwis    16 年前

    您需要将继承声明为虚拟继承:

    struct AbsBase {
              virtual void init() = 0;
              virtual void work() = 0;
    };
    
    struct AbsInit : virtual public AbsBase {
              void init() {  }
    };
    
    struct AbsWork : virtual public AbsBase {
              void work() { }
    };
    
    struct NotAbsTotal : virtual public AbsInit, virtual public AbsWork {
    };
    
    void f(NotAbsTotal *p)
    {
            p->init();
    }
    
    NotAbsTotal x;
    
        3
  •  1
  •   James Curran    16 年前

    这是可以做到的,尽管它让大多数人发抖。

    您需要使用“虚拟继承”,其语法类似于

    class AbsInit: public virtual AbsBase {...};
    class AbsWork: public virtual AbsBase {...};
    class NotAbsTotal: public AbsInit, public AbsWork {...};
    

    然后必须指定要使用的函数:

    NotAbsTotal::work()
    {
        AbsInit::work_impl();
    }
    

    (用正确的语法更新)

        4
  •  0
  •   Rob Wells    16 年前

    你必须开始思考你想在这里建立什么样的模型。

    公共继承只能用来建立“is a”关系的模型,例如狗是动物,正方形是形状等等。

    看看Scott Meyer的书《有效C++》,一篇关于OO设计的各个方面应该被解释为什么的优秀论文。

    编辑:我忘了说,虽然迄今为止提供的答案在技术上是正确的,但我认为它们中没有任何一个能解决您试图模拟的问题,这就是您问题的关键所在!

    高温高压

    干杯,

    抢劫

        5
  •  0
  •   Techman92    11 年前

    我在下面的链接中找到了一个简单的好例子。本文以一个计算矩形面积和周长的程序为例进行了说明。你可以查一下……干杯

    多级继承是一种继承层次结构,其中一个派生类继承多个基类。多读…

    http://www.mobihackman.in/2013/09/multiple-inheritance-example.html