代码之家  ›  专栏  ›  技术社区  ›  MOnsDaR

C++中的接口继承

  •  15
  • MOnsDaR  · 技术社区  · 16 年前

    我的班级结构如下:

    class InterfaceA
    { 
       virtual void methodA =0;
    }
    
    class ClassA : public InterfaceA
    {
       void methodA();
    }
    
    class InterfaceB : public InterfaceA
    {
       virtual void methodB =0;
    }
    
    class ClassAB : public ClassA, public InterfaceB
    { 
       void methodB(); 
    }
    

    现在,以下代码不可编译:

    int main()
    {
        InterfaceB* test = new ClassAB();
        test->methodA();
    }
    

    编译器说这个方法 methodA() ClassA InterfaceA ). 有人知道我的错在哪里吗?

    4 回复  |  直到 16 年前
        1
  •  23
  •   Atul Kumar    11 年前

    那是因为你有两份 InterfaceA . 请参阅以下内容以了解更详细的解释: https://isocpp.org/wiki/faq/multiple-inheritance (你的处境类似于“可怕的钻石”)。

    virtual 当您从InterfaceA继承ClassA时。您还需要添加 事实上的

        2
  •  10
  •   Atul Kumar    11 年前

    劳拉建议的虚拟继承当然是问题的解决方案。但它最终并不是只有一个接口。例如,它也有“副作用” https://isocpp.org/wiki/faq/multiple-inheritance#mi-delegate-to-sister

    如果您不想要副作用,可以使用模板:

    struct InterfaceA
    { 
      virtual void methodA() = 0;
    };
    
    template<class IA>
    struct ClassA : public IA //IA is expected to extend InterfaceA
    {
      void methodA() { 5+1;}
    };
    
    struct InterfaceB : public InterfaceA
    {
      virtual void methodB() = 0;
    };
    
    struct ClassAB 
      : public ClassA<InterfaceB>
    { 
      void methodB() {}
    };
    
    int main()
    {
      InterfaceB* test = new ClassAB();
      test->methodA();
    }
    

    所以,我们只有一个父类。

    但当有多个“共享”类时,它看起来更难看(InterfaceA是“共享的”,因为它位于“可怕的钻石”之上,请参见此处) https://isocpp.org/wiki/faq/multiple-inheritance 由劳拉发布)。参见示例(如果ClassA也实现了interfaceC,将是什么):

    struct InterfaceC
    {
      virtual void methodC() = 0;
    };
    
    struct InterfaceD : public InterfaceC
    {
      virtual void methodD() = 0;
    };
    
    template<class IA, class IC>
    struct ClassA
      : public IA //IA is expected to extend InterfaceA
      , public IC //IC is expected to extend InterfaceC
    {
      void methodA() { 5+1;}
      void methodC() { 1+2; }
    };
    
    struct InterfaceB : public InterfaceA
    {
      virtual void methodB() = 0;
    };
    
    struct ClassAB
      : public ClassA<InterfaceB, InterfaceC> //we had to modify existing ClassAB!
    { 
      void methodB() {}
    };
    
    struct ClassBD //new class, which needs ClassA to implement InterfaceD partially
      : public ClassA<InterfaceB, InterfaceD>
    {
      void methodB() {}
      void methodD() {}
    };
    

    糟糕的是,您需要修改现有的ClassAB。但你可以写:

    template<class IA, class IC = interfaceC>
    struct ClassA
    

    然后ClassAB保持不变:

    struct ClassAB 
          : public ClassA<InterfaceB>
    

    并且您有模板参数IC的默认实现。

    使用哪种方法由您决定。我更喜欢模板,因为它很容易理解。很难养成习惯,B::incrementAndPrint()和C::incrementAndPrint()将打印不同的值(不是您的示例),请参见以下内容:

    class A
    {
    public:
      void incrementAndPrint() { cout<<"A have "<<n<<endl; ++n; }
    
      A() : n(0) {}
    private:
      int n;
    };
    
    class B
      : public virtual A
    {};
    
    class C
      : public virtual A
    {};
    
    class D
      : public B
      : public C
    {
    public:
      void printContents()
      {
        B::incrementAndPrint();
        C::incrementAndPrint();
      }
    };
    
    int main()
    {
      D d;
      d.printContents();
    }
    

    以及输出:

    A have 0
    A have 1
    
        3
  •  4
  •   Andy    16 年前

    这个问题存在是因为C++没有真正的接口,只有纯继承的虚拟类。编译器不知道在哪里可以找到的实现 methodA() ClassAB . 您可以通过实现 方法a() 在里面 ClassAB()

    class ClassAB : public ClassA, public InterfaceB
    { 
        void methodA()
        {
            ClassA::methodA();
        }
    
        void methodB(); 
    }
    
        4
  •  2
  •   BostonLogan    16 年前