C++ 当两个继承的类都需要一个不同的成员时,如何处理多重继承?

C++ 当两个继承的类都需要一个不同的成员时,如何处理多重继承?,c++,multiple-inheritance,ambiguous,virtual-inheritance,C++,Multiple Inheritance,Ambiguous,Virtual Inheritance,我有以下课程: 类伺服部件{ 受保护的: 虚拟void doJob(字节*作业)=0; 私人: 布尔移动; 伺服; }; //以下类只有一个构造函数,因此我可以使用两个ServoPart从中继承 班级专业:公共服务部分{}; 小修班:公立{}; 班级:公共专业,公共小修{ 私人: 无效移动(){ //做事 如果(目标==当前){ 移动=假; } }; 公众: void doJob(byte*job){/*dostuff*/}; }; 我不能使用虚拟继承(我认为),因为主控和次控需要控制一个伺服

我有以下课程:

类伺服部件{
受保护的:
虚拟void doJob(字节*作业)=0;
私人:
布尔移动;
伺服;
};
//以下类只有一个构造函数,因此我可以使用两个ServoPart从中继承
班级专业:公共服务部分{};
小修班:公立{};
班级:公共专业,公共小修{
私人:
无效移动(){
//做事
如果(目标==当前){
移动=假;
}
};
公众:
void doJob(byte*job){/*dostuff*/};
};
我不能使用虚拟继承(我认为),因为主控和次控需要控制一个伺服,而每个伺服不可能是相同的。但是,当手臂完成移动时,它应该将
移动
成员设置为false。当im键入移动时,Intellisense显示
ServoPart::移动


移动的访问是否不明确?如果是,如何解决此问题?是我关于虚拟继承的假设,我不能使用它,因为我有两个不同的伺服,对吗?

是的,它是不明确的,编译器会抱怨。 您可以在
Arm
的成员函数的代码中编写
Major::moving
Minor::moving
,以指定所需的函数

我怀疑你在这里是否有一个合适的“isa”关系。手臂不是马达。手臂有两个马达。您应该在这里使用组合而不是继承。请注意,
Major
Minor
没有任何虚拟函数,因此没有理由选择继承

尝试:

现在更明显的是如何引用组件。但对于(多重)继承,这是相同的想法。我认为你也在引入
Major
Minor
的名称,只是为了绕过继承多个副本的限制。如果使用合成,可以避免:

class Arm {
   ServoPart major;
   ServoPart minor;
...
或者,因为它们现在是相同的类型,所以可以改为创建一个数组。这使得向所有人“广播”相同的操作变得容易:

class Arm {
    ServoPart joints[2];
    void move() {
        ...
        for (auto j : joints)  j.moving= false;
使现代化 您的评论表明
ServoPart
具有虚拟的
doJob
功能。您应该将其分离为一个没有数据成员的纯接口,并从中派生出单个motor类。您的合成类也可以从该接口继承

struct Servo_Interface {
    virtual void doJob() =0;
};

class Joint : Servo_Interface {
    bool moving;
    Servo servo;
public:
    void doJob()  override;
};

class Arm : Servo_Interface {
    Joint joints[2];
public:
    void doJob()  override;
};

请注意,
Arm
中的
doJob
的实现可以为它包含的每个组件调用
doJob
,但它是一个独立的函数,不自动依赖它们。单个
Joint
Arm
实例都可以进行多态处理,因为它们有一个公共接口。

是的,它是不明确的,编译器会抱怨。
struct Servo_Interface {
    virtual void doJob() =0;
};

class Joint : Servo_Interface {
    bool moving;
    Servo servo;
public:
    void doJob()  override;
};

class Arm : Servo_Interface {
    Joint joints[2];
public:
    void doJob()  override;
};
您可以在
Arm
的成员函数的代码中编写
Major::moving
Minor::moving
,以指定所需的函数

我怀疑你在这里是否有一个合适的“isa”关系。手臂不是马达。手臂有两个马达。您应该在这里使用组合而不是继承。请注意,
Major
Minor
没有任何虚拟函数,因此没有理由选择继承

尝试:

现在更明显的是如何引用组件。但对于(多重)继承,这是相同的想法。我认为你也在引入
Major
Minor
的名称,只是为了绕过继承多个副本的限制。如果使用合成,可以避免:

class Arm {
   ServoPart major;
   ServoPart minor;
...
或者,因为它们现在是相同的类型,所以可以改为创建一个数组。这使得向所有人“广播”相同的操作变得容易:

class Arm {
    ServoPart joints[2];
    void move() {
        ...
        for (auto j : joints)  j.moving= false;
使现代化 您的评论表明
ServoPart
具有虚拟的
doJob
功能。您应该将其分离为一个没有数据成员的纯接口,并从中派生出单个motor类。您的合成类也可以从该接口继承

struct Servo_Interface {
    virtual void doJob() =0;
};

class Joint : Servo_Interface {
    bool moving;
    Servo servo;
public:
    void doJob()  override;
};

class Arm : Servo_Interface {
    Joint joints[2];
public:
    void doJob()  override;
};

请注意,
Arm
中的
doJob
的实现可以为它包含的每个组件调用
doJob
,但它是一个独立的函数,不自动依赖它们。“单<代码>联合< /代码>和<代码> ARM 实例可以被多态地处理,因为它们有一个公共接口。

看起来是一个考虑组合而不是继承的好时机。composition@user4581301我用了“是一个”vs“有一个”的方法:手臂是一个伺服部件,包含两个伺服的。我想现在我将存储主要和次要的
移动
状态,并在检查状态时合并它们。如果我一直遇到这样的问题,我会重新考虑。我再次更新了我的答案。具有虚拟功能是改变性质的重要信息。小心不要过度简化示例代码@是的,我现在明白了。我会记住以后的问题。谢谢看起来是一个考虑写作而不是继承的好时机。composition@user4581301我用了“是一个”vs“有一个”的方法:手臂是一个伺服部分,包含两个伺服。我想现在我将存储主要和次要的
移动
状态,并在检查状态时合并它们。如果我一直遇到这样的问题,我会重新考虑。我再次更新了我的答案。具有虚拟功能是改变性质的重要信息。小心不要过度简化示例代码@是的,我现在明白了。我会记住以后的问题。谢谢我想我将分别存储每个伺服
移动
状态,然后在需要检查状态时将两者合并。谢谢我更新了这篇文章,建议使用合成而不是继承
struct Servo_Interface {
    virtual void doJob() =0;
};

class Joint : Servo_Interface {
    bool moving;
    Servo servo;
public:
    void doJob()  override;
};

class Arm : Servo_Interface {
    Joint joints[2];
public:
    void doJob()  override;
};