【问题标题】:How to handle multiple inheritance when both inherited classes need a distinct member?当两个继承的类都需要不同的成员时,如何处理多重继承?
【发布时间】:2021-05-18 15:49:12
【问题描述】:

我有以下课程:

class ServoPart {
protected:
    virtual void doJob(byte* job) = 0;

private:
    bool moving;
    Servo servo;
};

// the following classes only have a constructor so I can use two ServoParts to inherit from
class Major: public ServoPart {};
class Minor: public ServoPart {};

class Arm: public Major, public Minor {
private:
    void move() {
        // do stuff
        if (target == current) {
            moving = false;
        }
    };

public:
    void doJob(byte* job) {/* do stuff */};
};

我不能使用虚拟继承(我认为),因为 Major 和 Minor 需要分别控制一个伺服,这不能相同。但是,当 Arm 完成移动时,它应该将 moving 成员设置为 false。当我输入 moving 时,Intellisense 显示 ServoPart::moving

moving 的访问是否会产生歧义?如果是,我该如何解决这个问题?我对虚拟继承的假设是否因为我有两个不同的伺服系统而无法使用它,对吗?

【问题讨论】:

  • 看起来是考虑组合而不是继承的好时机。
  • 继承在这里感觉不是正确的方法,我会考虑组合
  • @user4581301 我使用了“is a”与“has a”的方法:手臂 is a 伺服部分,包含两个伺服。我想现在我将为主要和次要存储moving 状态,并在检查状态时将它们结合起来。如果我继续遇到这样的问题,我会重新考虑
  • re doJob 我再次更新了我的答案。具有虚拟功能是改变性质的重要信息。注意不要过度简化示例代码!
  • @JDługosz 是的,我现在可以看到了。我会记住以后的问题。谢谢!

标签: c++ multiple-inheritance ambiguous virtual-inheritance


【解决方案1】:

是的,它是模棱两可的,编译器会抱怨。 你可以在Arm的成员函数的代码中写Major::movingMinor::moving来指定你想要的。

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

试试:

class Arm {
   Major major;
   Minor minor;
   void move() {
     ...
     major.moving= false;
     minor.moving= false;
     ...

现在如何引用组件更明显了。但是对于(多重)继承,这是相同的想法。我认为您还介绍了名称MajorMinor 只是为了绕过继承多个副本的限制。如果您使用合成,则可以避免这种情况:

class Arm {
   ServoPart major;
   ServoPart minor;
...

或者,既然它们现在是相同的类型,也许可以创建一个数组。这使得向所有人“广播”相同的操作变得容易:

class Arm {
    ServoPart joints[2];
    void move() {
        ...
        for (auto j : joints)  j.moving= false;

更新

您的评论表明ServoPart 具有虚拟doJob 功能。您应该将其分离成一个没有数据成员的纯 interface,并从中派生出您的单电机类。您的复合类也可以从该接口继承。

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,但它是一个单独的函数,不会自动依赖它们。单个 JointArm 实例都可以进行多态处理,因为它们具有通用接口。

【讨论】:

  • 我想我会分别存储每个伺服器moving 状态然后在需要检查状态时将两者结合起来。谢谢!
  • 我更新了帖子,建议使用组合而不是继承。
  • 我在帖子中遗漏了一些我应该添加的东西,那就是ServoPart 有一个抽象函数doJob,它需要工作。我想我可以在 Major 和 Minor 中实现该功能并让它什么都不做,但这不会让人感觉干净。基本上,Arm 完成一项工作并设置每个伺服系统的位置。 Major/Minor 类自己不能这样做,因为位置取决于另一部分的位置。
  • @matthesinator 我再次更新了答案。
猜你喜欢
  • 2012-03-30
  • 2011-09-24
  • 1970-01-01
  • 1970-01-01
  • 2019-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-13
相关资源
最近更新 更多