27

我有一个充当接口的抽象基类。

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

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

所以:(错误的伪代码)

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
}

首先,我可以这样做吗?我可以从两个派生自同一个 Base 的类继承吗?(但愿如此)。

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

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

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++ 在尝试使用该类时抱怨说:“对成员 init() 的请求不明确”。

我假设,如果我将 AbsBase 类用作纯接口,这将是可以避免的(假设上面的例子是有效的)。

所以: - 我的实施是否可行?- 这是将虚拟方法设为私有的习语的限制吗?- 我如何重构我的代码来做我想做的事?(提供一个通用接口,但允许使用一种方法来交换成员函数“集合”的实现)

编辑:

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

似乎虚拟继承是这里的解决方案。我以前听说过虚拟继承,但我还没有深入了解它。我仍然愿意接受建议。

4

5 回答 5

35

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


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

基本上,默认的非虚拟多重继承将包括派生类中每个基类的副本,并包括它们的所有方法。这就是为什么您有两个 AbsBase 副本的原因——您的方法使用不明确的原因是两组方法都已加载,因此 C++ 无法知道要访问哪个副本!

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

于 2008-10-31T19:47:54.540 回答
1

它可以做到,尽管它让大多数人不寒而栗。

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

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

然后您必须指定要使用的功能:

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

(用正确的语法更新)

于 2008-10-31T19:43:29.337 回答
1

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

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;
于 2008-10-31T19:46:01.220 回答
0

您必须开始考虑您要在这里建模的内容。

公共继承只能用于模拟“isa”关系,例如狗是动物,正方形是形状等。

查看 Scott Meyer 的《Effective C++》一书,了解 OO 设计的各个方面只能被解释为什么的优秀文章。

编辑:我忘了说,虽然到目前为止提供的答案在技术上是正确的,但我认为它们中的任何一个都不能解决你试图建模的问题,这就是你问题的症结所在!

高温高压

干杯,

于 2008-11-01T01:05:26.113 回答
0

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

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

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

于 2013-09-03T00:45:24.567 回答