Как дать свойства классам (интерфейсам) c ++ - PullRequest
0 голосов
/ 28 мая 2010

Я построил несколько классов (A, B, C ...), которые выполняют операции над одним и тем же 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(); } }

Но, как вы можете видеть, каждый класс A, B, C ... использует только подмножество доступных методов 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), и это не всегда возможно и не желательно.

Ответы [ 3 ]

0 голосов
/ 28 мая 2010

Должны ли абоненты метода A, 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);
0 голосов
/ 29 мая 2010

шаблон использования Адаптер

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);
0 голосов
/ 28 мая 2010

Я не вижу ничего плохого в производном классе, который не использует некоторые элементы своего базового класса.

Производный класс не является обязательным для использования всего доступного для него.

Следовательно, я не вижу ничего плохого в вашей первоначальной реализации, и нет необходимости ее реорганизовывать.

...