来自两个派生类的多重继承
我有一个作为接口的抽象基类。
我有两组派生类,它们实现了抽象类的一半。 (一个“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
}
首先,我可以这样做吗? 我可以从两个派生自同一个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
似乎虚拟继承是这里的解决方案。 我以前听说过虚拟继承,但是我没有把头绕在它周围。 我仍然乐于接受建议。
它看起来像你想做虚拟继承。 事实证明这是否是一个好主意是另一个问题,但以下是你如何做到的:
class AbsBase {...};
class AbsInit: public virtual AbsBase {...};
class AbsWork: public virtual AbsBase {...};
class NotAbsTotal: public AbsInit, public AbsWork {...};
基本上,默认的非虚拟多重继承将在派生类中包含每个基类的副本,并包含其所有方法。 这就是为什么你有两个AbsBase副本 - 并且你的方法使用的原因是模糊的,因为两组方法都被加载,所以C ++无法知道要访问哪个副本!
虚拟继承将所有对虚拟基类的引用压缩为一个数据结构。 这应该使来自基类的方法再次明确。 但是,请注意:如果两个中间类中有其他数据,则可能会产生一些额外的运行时开销,以使代码能够找到共享的虚拟基类。
您需要将继承声明为虚拟:
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;
它可以做到,尽管它让人不寒而栗。
你需要使用“虚拟继承”,其语法是类似的
class AbsInit: public virtual AbsBase {...};
class AbsWork: public virtual AbsBase {...};
class NotAbsTotal: public AbsInit, public AbsWork {...};
然后你必须指定你想要使用的功能:
NotAbsTotal::work()
{
AbsInit::work_impl();
}
(用正确的语法更新)
链接地址: http://www.djcxy.com/p/54827.html