我有一个抽象基类,它充当接口。
我有两个派生类的“集合”,它实现了抽象类的一半。 (一个“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继承了“each of each”(我意识到我可能正在屠杀编译时真正发生的事情)。
无论如何,g ++抱怨说:“当尝试使用该类时,”成员init()的请求是不明确的。
我认为,如果我将AbsBase类用作纯接口,则可以避免(假设顶部示例有效)。
所以: - 我的实施方式是否可行? - 这是将虚拟方法设为私有的习惯用法的限制吗? - 我如何重构我的代码来做我想要的? (提供一个通用接口,但允许一种方法来替换成员函数“集合”的实现)
编辑:
似乎我不是第一个: http://en.wikipedia.org/wiki/Diamond_problem
似乎虚拟继承是这里的解决方案。我之前听说过虚拟继承,但我没有把头包裹起来。我仍然愿意接受建议。
答案 0 :(得分:35)
看起来你想做虚拟继承。是否真的是一个好主意是另一个问题,但这是你如何做到的:
class AbsBase {...};
class AbsInit: public virtual AbsBase {...};
class AbsWork: public virtual AbsBase {...};
class NotAbsTotal: public AbsInit, public AbsWork {...};
基本上,默认的非虚拟多重继承将在派生类中包含每个基类的副本,并包括它们的所有方法。这就是为什么你有两个AbsBase副本 - 你的方法使用不明确的原因是加载了两组方法,所以C ++无法知道要访问哪个副本!
虚拟继承将对虚拟基类的所有引用压缩为一个数据结构。这应该使基类中的方法再次明确。但是,请注意:如果两个中间类中有其他数据,则可能会有一些额外的运行时开销,以使代码能够找到共享的虚拟基类。
答案 1 :(得分:1)
它可以做到,虽然它给了大多数人的颤抖。
您需要使用“虚拟继承”,其语法类似于
class AbsInit: public virtual AbsBase {...};
class AbsWork: public virtual AbsBase {...};
class NotAbsTotal: public AbsInit, public AbsWork {...};
然后你必须指定你想要使用的功能:
NotAbsTotal::work()
{
AbsInit::work_impl();
}
(用正确的语法更新)
答案 2 :(得分: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;
答案 3 :(得分:0)
你必须开始考虑你想要在这里建模的术语。
公共继承只应用于建模“isa”关系,例如:狗是动物,方形是形状等。
请参阅Scott Meyer的书“Effective C ++”,这篇文章是关于OO设计的各个方面应该被解释为什么的优秀论文。
编辑:我忘了说尽管到目前为止提供的答案在技术上是正确的,但我认为它们中的任何一个都没有解决你想要建模的问题,这是你问题的症结所在!
HTH
欢呼声,
罗布
答案 4 :(得分:0)
我在下面的链接中找到了一个简单的例子。本文解释了一个用于计算矩形的面积和周长的示例程序。你可以查一下......工作人员
多级继承是一种继承层次结构,其中一个派生类继承自多个基类。阅读更多..
http://www.mobihackman.in/2013/09/multiple-inheritance-example.html