Как уменьшить дублирование кода в классе с элементами данных с одинаковым именем, но разным типом?

У меня проблемы с созданием таких классов

class C1 {
public:
  void foo();
}

class C2 {
public:
  void foo();
}

C1 и C2 имеют один и тот же метод foo(),

class Derived1 : public Base {
public:
  void Update() {
    member.foo();
  }
private:    
  C1 member;
}

class Derived2 : public Base {
public:
  void Update() {
    member.foo(); 
  }
private:    
  C2 member;
}

Update() обоих производных классов абсолютно одинаковы, но тип члена отличается. Поэтому мне нужно скопировать реализацию Update для каждого нового производного класса.

Это способ уменьшить дублирование кода? Я только выхожу с решением с макросом. Я думаю, что есть более элегантный способ решить эту проблему с помощью шаблона, но я не могу понять.

EDIT: большое спасибо, ребята, но я думаю, что я что-то пропустил..

1. Я использую С++

2. На самом деле каждый производный класс имеет около 5 членов, все они предоставляют метод foo() и являются производными от одного и того же базового класса. Моя ситуация такова, что я уже написал (очень длинный) метод Update(), и он может работать для каждого производного класса без каких-либо изменений. Поэтому я просто копирую и вставляю этот Update() в Update() каждого нового класса, и это приводит к ужасному дублированию кода. Интересно, есть ли способ, с помощью которого мне не нужно слишком много переписывать Update() и можно уменьшить дублирование.

спасибо еще раз


person jagttt    schedule 08.05.2009    source источник


Ответы (4)


Это именно то приложение, для которого предназначены шаблоны классов. Они позволяют функциям внутри класса работать с разными типами данных без необходимости копировать алгоритмы и логику.

Эта страница Википедии даст вам хороший обзор шаблонов в программировании.

Вот основная идея для начала:

template  <class T>
class CTemplateBase
{
public:
    void Update()
    {
        member.foo();
    }
private:
    T member; // Generic type
}

class CDerived1 : public CTemplateBase<C1>
{
    // No common algorithms required here
}

class CDerived2 : public CTemplateBase<C2>
{
    // No common algorithms required here
}
person LeopardSkinPillBoxHat    schedule 08.05.2009
comment
Вместо этих производных, почему бы просто не использовать: typedef Dervied1 CTemplateBase‹C1›; и typedef Dervied2 CTemplateBase‹C2›; (очевидно, что производное больше не является хорошим именем, но вы поняли). - person user83255; 08.05.2009
comment
@ilproxil - Да, я думаю, это приемлемо. Но я оставлю это как есть для ясности. - person LeopardSkinPillBoxHat; 11.05.2009

Если у вас есть контроль над C1 и C2, вы можете либо определить базовый класс, либо абстрактный базовый класс и обрабатывать его в базовом классе или третьем вспомогательном классе.

person Eugene Yokota    schedule 08.05.2009

Если ваши Drived1 и Derived2 одинаковы, за исключением типа (C1 и C2) члена, вы можете рассмотреть возможность использования одного класса Derived и шаблона. (Извините за синтаксис, если он неправильный, я C# dev :D)

template <class T>
class Derived : public Base {
public:
  void Update() {
    member.foo();
  }
private:    
  T member;
}

Что-то из вышеперечисленных строк.

person SO User    schedule 08.05.2009

Переместите метод в родительский класс:

class IFooable {
public:
  virtual void foo() = 0;
}

class C1 : IFooable {
public:
  void foo();
}

class C2 : IFooable {
public:
  void foo();
}

class Base {
public:
  void Update() {
    member->foo(); 
  }
private:    
  IFooable* member
}

class Derived1 : public Base {
  Derived1 () : member(new C1()) {}
  ~Derived1 () { delete member; }
}

class Derived2 : public Base {
  Derived2 () : member(new C2()) {}
  ~Derived2 () { delete member; }
}
person Community    schedule 08.05.2009
comment
Это С++, а не С#. Член должен быть указателем, а не экземпляром. Мало того, что полиморфизм не будет работать, это не скомпилируется. Я думаю, что вы на правильном пути, и я предпочитаю это шаблонному решению (хотя мне трудно найти не субъективную причину). - person Andrew Shepherd; 08.05.2009
comment
Спасибо, это было некоторое время на моем C++. элемент был изменен на указатель. - person Nick Whaley; 08.05.2009
comment
IFooable также нуждается в виртуальном деструкторе, если вы собираетесь удалять указатели типа IFooable*. - person Steve Jessop; 08.05.2009