【问题标题】:How to give properties to c++ classes (interfaces)如何为 c++ 类(接口)赋予属性
【发布时间】:2010-05-28 18:27:42
【问题描述】:

我已经构建了几个类(ABC...),它们对相同的BaseClass 执行操作。示例:

struct BaseClass {
    int method1();
    int method2();
    int method3();
}
struct A { int methodA(BaseClass& bc) { return bc.method1(); } }
struct B { int methodB(BaseClass& bc) { return bc.method2()+bc.method1(); } }
struct C { int methodC(BaseClass& bc) { return bc.method3()+bc.method2(); } }

但正如您所见,每个类 ABC... 仅使用 BaseClass 的可用方法的子集,我想将 BaseClass 拆分为几个块,以便清楚它使用了什么,什么不是。例如,一个解决方案可能是使用多重继承:

// A uses only method1()
struct InterfaceA { virtual int method1() = 0; }
struct A { int methodA(InterfaceA&); }

// B uses method1() and method2()
struct InterfaceB { virtual int method1() = 0; virtual int method2() = 0; }
struct B { int methodB(InterfaceB&); }

// C uses method2() and method3()
struct InterfaceC { virtual int method2() = 0; virtual int method3() = 0; }
struct C { int methodC(InterfaceC&); }

问题是每次添加新类型的操作,都需要更改BaseClass的实现。例如:

// D uses method1() and method3()
struct InterfaceD { virtual int method1() = 0; virtual int method3() = 0; }
struct D { int methodD(InterfaceD&); }

struct BaseClass : public InterfaceA, public InterfaceB, public InterfaceC
// here I need to modify the existing code to add class D
{ ... }

你知道我可以做到这一点的干净方法吗?

感谢您的帮助

编辑:

我忘了提到它也可以用模板来完成。但我也不喜欢这个解决方案,因为所需的接口没有明确出现在代码中。您必须尝试编译代码以验证是否正确实现了所有必需的方法。另外,它需要实例化不同版本的类(每个 BaseClass 类型模板参数一个),这并不总是可行的,也不可取。

【问题讨论】:

    标签: c++ interface multiple-inheritance


    【解决方案1】:

    使用模式Adapter

    struct InterfaceA { virtual int method1() = 0; }
    
    struct A { int methodA(InterfaceA& bc) { return bc.method1(); } }
    
    struct BaseClassAdapterForA: public InterfaceA 
    { 
       BaseClassAdapterForA(BaseClass& _bc) : bc(_bc) {}
       virtual int method1() 
       { 
           //note that the name of BaseClass method 
           //can be anything else
            return bc.method1(); 
            // or return bc.whatever();
       }
    private:
       BaseClass& bc;
    };
    //usage
    BaseClass bc;
    A a;
    BaseClassAdapterForA bca(bc);
    a.methodA(bca);
    

    【讨论】:

    • 这正是我所需要的!谢谢
    【解决方案2】:

    我认为派生类不使用其基类的某些元素没有任何问题。

    派生类不需要也不应该被要求使用它可用的一切

    因此,我认为您的原始实现没有任何问题,无需重构。

    【讨论】:

    • 您好,感谢您花时间回答。事实是:A 类只需要一个实现InterfaceA 的类。使A 依赖于/all/ 的BaseClass 的方法使其难以重用。例如,仅仅因为我希望能够将它与A(而不是BC)一起使用就要求BaseClass2 实现所有BaseClass 的方法会太痛苦。你明白了吗?
    【解决方案3】:

    methodA、methodB、...的调用者是否应该知道实际使用了1、2、3中的哪些方法?

    如果这样做,您可以将 BaseClass 拆分为 3 个不同的接口,并准确添加方法 1、2 和 3 所需的接口参数,如下所示:

    class Interface1 {virtual int method1() = 0;};
    class Interface2 {virtual int method2() = 0;};
    class Interface3 {virtual int method3() = 0;};
    
    class A
       {
       int methodA(Interface1 &i1)
          {
          return i1.method1();
          }
       };
    
    class B
       {
       int methodB(Interface1 &i1, Interface2 &i2)
          {
          return i1.method1() + i2.method2();
          }
       };
    
    class C
       {
       int methodC(Interface2 &i2, Interface3 &i3)
          {
          return i2.method2() + i3.method3();
          }
       };
    

    调用者仍然可以选择从多个接口继承,像这样:

    class MyClass : public Interface2, public Interface3
       {
       int method2() {...}
       int method3() {...}
       };
    ...
    MyClass myClass;
    C c;
    c.methodC(myClass,myClass);
    

    【讨论】:

    • 不要忘记,在 C++ 中,method1()method2()method3() 必须是虚拟的,否则多态不会发挥作用。
    • 根据BaseClass::methodN 的作用,没有必要将方法设为虚拟。此外,非虚拟接口总是有可能的。 (en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-Virtual_Interface)
    • @In silico,你是对的。我有点仓促。对其进行了编辑以使其再次正确。
    • 谢谢;很好的讨论和链接。不幸的是,接口方法太多,无法将它们作为参数传递。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-11-11
    • 2012-12-03
    • 1970-01-01
    • 1970-01-01
    • 2020-10-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多