Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Наследование vs параметризация  (Прочитано 14882 раз)
0 Пользователей и 1 Гость смотрят эту тему.
ysv_
Помогающий

ua
Offline Offline

« : 05-09-2006 16:26 » 

Кто-нибудь встречал какие либо статьи по сабжу для реализации настраиваемого на этапе компиляции поведения?
Имеется в виду сравнение двух реализаций изменяемого поведения:
1) через наследование:
Код:
class IA
{
public:
   virtual void method()=0;
...
};

class A1: public IA
{
public:
   virtual void method() {...}
...
};

class A2: public IA
{
public:
   virtual void method() {...}
...
};

class B
{
public:
  B(IA* a) {...}
  void method() {...; a->mathod(); ...}
private:
  IA* a;
};

A1 a1;
A2 a2;
B b1i(&a1);
B b2i(&a2);

2) через шаблон:
Код:
class A1
{
public:
   void method() {...}
...
};

class A2
{
public:
   void method() {...}
...
};

template <typename A> class B
{
public:
  B() {...}
  void method() {...; a.method(); ...}
private:
  A a;
};

B<A1> b1t;
B<A2> b2t;

В результате имеем два екземпляра объекта B c различным поведением. Причем методы b1i и b1t инвариантны относительно выполняемых функций.
Записан
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #1 : 06-09-2006 05:03 » 

ysv_, Александреску "Современный дизайн C++" прямо первые две главы всё очень хорошо расписано, то о чем ты спрашивает называется стратегии(policy) и свойства(trait)
также можно посмотреть реализацию стандартных контейнеров и аллокаторов, аллокатор переданный вектору в качестве параметра шаблона по сути является стратегией распределения памяти.
это всё обычно называют статическим полиморфизмом в противоположность динамическому полиморфизму реализуемому через виртуализацию.

в общем Александреску тебя должен помоч.
Записан

Странно всё это....
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #2 : 06-09-2006 06:50 » 

Почему "vs"? Можно и сочетать Улыбаюсь. В какой-то теме здесь было:
Код:
template<class X>
class Y : public X
{
   ...
};
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #3 : 06-09-2006 06:57 » 

кстати да Улыбаюсь
Записан

Странно всё это....
ysv_
Помогающий

ua
Offline Offline

« Ответ #4 : 06-09-2006 08:59 » 

LogRus, спасибо!
dimka, "Почему "vs"?" - интересовало сравнение и в каких случаях чему отдается предпочтение.
Записан
Alf
Гость
« Ответ #5 : 06-09-2006 09:50 » 

IMHO сама постановка вопроса некорректна. Все равно что обсуждать тему типа "циклы vs структуры" - исходно разные концепции, задуманные для разных целей. Каждая из них уместна в том контексте, для которого предназначена, и выглядит несколько натянуто в других ситуациях.

Задача шаблона - параметризовать конкретную реализацию алгоритма или класса на основе шаблона, этакое изощренное подобие макроса. Задача наследования - предоставить механизм, позволяющий на основании более общего класса создать его более специализированную версию, поддерживающую интерфейс родителя, но имеющую отличия в поведении. Сложно такие разные вещи сравнивать.
Записан
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #6 : 06-09-2006 10:25 » 

Alf, почему подходы нельзя сравнивать?
вполне можно сравнивать и совмещать
и категорически не согласен с этим
этакое изощренное подобие макроса
совершенно разные вещи
Записан

Странно всё это....
Alf
Гость
« Ответ #7 : 06-09-2006 11:00 » 

А в чем конкретно не согласен? В чем принципиальная разница?
Записан
Alf
Гость
« Ответ #8 : 06-09-2006 11:32 » new

Вот подвернулся Буч под руку:

Цитата
Наследование без полиморфизма возможно, но не очень полезно. Это видно на примере Ada, где можно объявлять производные типы, но из-за мономорфизма языка операции жестко задаются на стадии компиляции.
 
Полиморфизм тесно связан с механизмом позднего связывания. При полиморфизме связь метода и имени определяется только в процессе выполнения программ. В C++ программист имеет возможность выбирать между ранним и поздним связыванием имени с операцией. Если функция виртуальная, связывание будет поздним и, следовательно, функция полиморфна. Если нет, то связывание происходит при компиляции и ничего изменить потом нельзя.

В случае шаблонов имеем подстановку параметра на этапе компиляции и генерацию отдельного кода для каждого возможного типа параметра. В случае наследования имеем позднее связывание и как следствие - полиморфное поведение на этапе выполнения программы. В первом случае получаем набор ничем не связанных реализаций, во втором - семейство родственных классов с общим предком, то есть приводимых к базовому типу. Неужели тут действительно такое сильное сходство, которое я не смог уловить?
Записан
ysv_
Помогающий

ua
Offline Offline

« Ответ #9 : 06-09-2006 13:42 » 

В моем случае оба варианта имеет смысл расматривать. А именно при написании юнит-тестов часто возникает ситуации, когда вместо реального объекта, ввиду его сложности, используется мок-объект. До вчерашнего дня я всегда в таких случаях объявлял интерфейс и реализовывал его в реальном и мок-объектах.
Например:
class IA {...}; // interface
class A: public IA {...}; // real class
class MockA: public IA {...}; // Mock class (for test purposes)
class B {public: B(IA* a) {...} ...};
Где-то в тесте:
MockA a;
B b(&a);

В принципе, когда все это делается исключительно для целей тестирования - вариант через статический полиморфизм виглядит по моему мнению как минимум не хуже. Вот я и хотел почитать мнение знающих людей.
Нравится меньшее количество накладных расходов. Не нужно задумываться над вопросом, кто будет создавать объекты А для их передачи экземплярам В.
Записан
Alf
Гость
« Ответ #10 : 06-09-2006 14:03 » 

Интересная идея. А каким образом можно будет без полиморфизма подсунуть мок вместо реального объекта, если они будут разных типов? Если два класса имеют одинаковый набор методов, это еще не значит, что мы сможем привести их к одному типу. А ведь именно к этому приведет использование шаблона.

В общем, любопытно увидеть работающий пример.
Записан
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #11 : 06-09-2006 17:40 » 

Лениво сейчас описывать отсылаю к Александреску.
Если завтра не забуду, то отвечу
Записан

Странно всё это....
ysv_
Помогающий

ua
Offline Offline

« Ответ #12 : 06-09-2006 18:20 » 

Пример из жизни. Несущественное поскипано.
class TestGraphWnd: public TestSet
{
public:
  TestGraphWnd(char const* name);
  virtual void init();
  virtual void deinit();

private:
  bool testOnPaint();

  CWnd *mParentWnd;
  GraphWnd<MockLabel>* mGraphWnd;
  MockLabel* mTitle;
};

void TestGraphWnd::init()
{
  mParentWnd=new CWnd();
  mParentWnd->CreateEx(0, AfxRegisterWndClass(0), 0, WS_VISIBLE, 0, 0, 600,
    400, 0, 0, 0);
  mGraphWnd=new GraphWnd<MockLabel>();
  mGraphWnd->create(mParentWnd);
  mTitle=mGraphWnd->getTitle();
}

bool TestGraphWnd::testOnPaint()
{
  mGraphWnd->OnPaint();
  TEST_CHECK(mTitle->getCallCount("draw")==1);
  return true;
}

В другом файле.
template <typename TitleType> class GraphWnd: public СWnd
{
public:
...
  afx_msg void OnPaint()
  {
    CPaintDC dc(this);
    mTitle.draw(dc);
  }
...
private:
  TitleType mTitle;
...
}

В еще одном файле.
class MockLabel
{
public:
  int getCallCount(char const* methodName)
  {
    return mCallList.getCallCount(methodName);
  }

  void draw(CDC& dc) //не виртуальная!!!
  {
    mCallList.push_back("draw");
  }

private:
  CallList mCallList;
};

Еще в одном файле.
class GraphView: public CWnd
{
...
  GraphWnd<Title> mGraphs[gmGraphCount];
...
};
Записан
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #13 : 07-09-2006 04:51 » 

Если два класса имеют одинаковый набор методов, это еще не значит, что мы сможем привести их к одному типу. А ведь именно к этому приведет использование шаблона.

Вот тут ты не прав. Ни чего не к какому типу приводить не надо.
Достататочно, то что набор методов и сигнатур(и не явных приведений приводящим к схожим сигнатурам) будет совпадать.
И то нужны только те методы, которые будут реально использованы.
Т.е. если инстанцирую шаблон класса A передавая в качестве аргумента класс B с усеченным интерфейсом(нехватаем методов), но не вызываю в коде методов класса A использующие недостающие методы B то код будет прекрасно работать (Николай Джосатис "Шаблоны C++")

Код:
template<class data>
class processdata
{
public:
template <class indata, class outdata>
bool doNext(indata i, outdata o)
{
data d;
bool bEof = false;
bEof = i.get(d);
// что-то делаем
o.put(d);
return bEof
}
}
я могу прекрасно этот код использовать в тестах отдавая заклушки в indata и outdata
Записан

Странно всё это....
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines