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

C++接口

c++
  •  5
  • danatel  · 技术社区  · 15 年前

    我想使用C++中的接口,比如java或C语言中的接口。我决定使用具有多重继承的纯抽象类,但当我专门化接口时,出现了严重错误:

    class Interface
    {
    public:
      virtual int method() = 0;
    };
    
    // Default implementation.
    class Base: virtual public Interface
    {
    public:
      virtual int method() {return 27;}
    };
    
    // specialized interface
    class Interface2: public Interface
    {
    public:
      virtual int method() = 0;
    // some other methods here
    };
    
    
    // concrete class - not specialised - OK
    class Class: public virtual Interface, public virtual Base
    {
    };
    
    // concrete class - specialised
    class Class2: public Interface2, public Base
    {
    };
    
    
    
    int main()
    {
      Class c;
      Class2 c2;
    return 0;
    }
    

    错误2错误C2259:“类2”:无法实例化抽象类42

    7 回复  |  直到 15 年前
        1
  •  5
  •   Tom    15 年前

    Class2继承自抽象类(Interface2),但没有实现纯虚方法,因此它仍然是一个抽象类。

        2
  •  4
  •   Pieter    15 年前

    基于此,

    If the method is not reimplemented in Class2 or Class (it is not in 
    this case) Base::method() will be called. Otherwise the reimplementation 
    will be called. There is an interface hierarchy with a common base 
    dumb implementation. 
    
    – danatel 16 mins ago
    

    这不是你所拥有的,你没有共同的基础,你有

    Interface -> Interface2 -> Class2
    Interface -> Base -> Class2
    

    接口未在派生树中“合并”,interface2实际上不会从接口继承,因此它将拥有自己的接口超类。 就像纯粹的虚拟世界 method() 在类2中存在两次,一次通过类实现,一次未实现。

    即使您实际上继承了,公共基础(接口)仍然没有实现

    如果这只是一个简单的例子,让问题变得简短,比如 Bridge Pattern 可能更有用。但如果你不了解更多,就很难进一步指导你。

        3
  •  4
  •   markh44    15 年前

    嘿嘿,这个问题让我的脑海深处有些东西发痒。我不能完全指出这一点,但我认为这与定义接口继承权,然后继承接口和实现有关。然后,通过将调用转发到基类,可以避免使用实现所有函数。我想。

    #include <iostream>
    using namespace std;
    
    struct Vehicle
    {
        virtual void Drive() = 0;
    };
    
    struct VehicleImp : virtual public Vehicle
    {
        virtual void Drive() 
        {
            cout << "VehicleImp::Drive\n";
        }
    };
    
    struct Tank : virtual public Vehicle
    { 
        virtual void RotateTurret() = 0;
    };
    
    struct TankImp : public Tank, public VehicleImp
    {
        virtual void RotateTurret() 
        {
            cout << "TankImp::RotateTurret\n";
        }
        // Could override Drive if we wanted
    };
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        TankImp myTank;
        myTank.Drive();         // VehicleImp::Drive
        myTank.RotateTurret();  // TankImp::RotateTurret
        return 0;
    }
    

    TankImp基本上继承了Tank接口和车辆实现。

    现在,我很确定这在OO圈中是一个众所周知和可以接受的东西(但我不知道它是否有一个花哨的名字),所以在这种情况下,可怕的钻石的东西是好的,你可以安全地抑制支配警告,因为这是你想在这种情况下发生的。

    希望这能帮助你找到正确的方向!

    编辑:

    好的,我想我现在更了解你的问题了,我认为错误在界面2。尝试将其更改为:

    // specialized interface
    class Interface2: public virtual Interface // ADDED VIRTUAL
    {
    public:
        //virtual int method() = 0;   COMMENTED THIS OUT
        // some other methods here
    };
    

    Interface2不应该有方法的纯虚拟定义,因为它已经在Interface中了。

        4
  •  3
  •   Steven    15 年前

    没有虚拟析构函数,如果执行以下操作,则会出现问题:

    Base *b = new Class2();
    delete b;
    
        5
  •  3
  •   Community CDub    7 年前

    关于 Class : 你所需要做的就是推导 Base --它实现的事实 Interface 这意味着,事实上,这是不可避免的:

    class Class: public Base  // virtual inheritance is unnecessary here
    {
    };
    

    method() 从…起 基础 如所愿。

    关于 Class2 :

    免责声明:前面是负面结果

    根据您对 Tom's answer 答案 类别2 :

    // concrete class - specialised
    class Class2: public Interface2, public Base
    {
    public:
        using Base::method;    // "Imports" all members named "method" from Base
    };
    

    第7.3.3节第14段解释如下: using 无法用于解决对继承成员的不明确访问:

    ... [注意:由于using声明指定基类成员(而不是成员子对象或基类子对象的成员函数),因此using声明不能用于解决继承的成员歧义….]

    看来,只有这样,才能获得理想的行为 类别2

    // concrete class - specialised
    class Class2: public Interface2, public Base
    {
    public:
         virtual int method() { return Base::method(); }
    };
    

    关于 virtual 继承: 不要 但是你可能 需要它吗 Interface2 的声明,以确保 类别2 只有一个类型为的子对象 界面 类别2 对象有两个此类型的子对象。(尽管如果 界面 事实上的 ,它作为一个独特的对象出现;与关键字一起出现的所有基类 都浓缩成一个对象。

    markh44's excellent answer 表明上述方法(制造 继承 从…起 界面 )事实上会允许 类别2 自动继承的实现 方法() 从…起 基础

        6
  •  2
  •   Daniel Daranas    15 年前

    This answer 在另一个论坛上,你似乎可以解决你提到的问题。

        7
  •  1
  •   Aaron Saarela    15 年前

                Interface
                /      \
              Base   Interface2
                \      /
                 Class2
    

    如果你不小心的话,这将导致你称之为一种悲伤。模棱两可会咬你的。

    在您的特定实例中,Interface2不需要从Interface继承。Interface2不需要指定“方法”,因为它是抽象的。删除Interface和Interface2之间的继承以打破菱形。然后,您将看到层次结构如下所示:

            Interface                Interface  Interface2
               |                          |       |
              Base                      Base      |
               |                           \      /
             Class                          Class2
    

    您的实现如下所示:

    // concrete class - not specialised - OK
    class Class: public Base
    {
    };
    
    // concrete class - specialised
    class Class2: public Base, public Interface2
    {
        virtual int method() {return 35;}
    
        virtual void Inteface2Method { ... }
    };