Форум программистов, компьютерный форум, киберфорум
C++
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.70/27: Рейтинг темы: голосов - 27, средняя оценка - 4.70
Evg
Эксперт CАвтор FAQ
21117 / 8133 / 628
Регистрация: 30.03.2009
Сообщений: 22,447
Записей в блоге: 30
1

Использование указателя на метод вместо виртуального метода

20.11.2010, 12:33. Просмотров 5296. Ответов 45
Метки нет (Все метки)

Имеется базовый класс Base. Имеется производный от Base класс Derived. В классе Derived требуется выполнить некоторое действие, которое практически полностью эквивалентно для любого производного от Base класса, за исключением небольшого фрагмента.

Схематично код выглядит так:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Base
{
  void Exec (void)
  {
    // общие действия
    ...
 
    // конкретные действия для производных классов
    Tail ();
  }
 
  virtual void Tail (void) = 0;
};
 
class Derived : public Base
{
  void MyExec (void)
  {
    // В процессе исполнения будет исполнен виртуальный метод Tail
    Exec ();
  }
 
  virtual void Tail (void)
  {
    // Определяем конкретные действия для нашего класса
  }
}
Однако при такой схеме возможен только один вид частных действия для производного класса. А хотелось бы, чтобы внутри производного класса можно было выполнять разные действия. Для этого логично было бы использовать указатель на метод. Т.е. что-то типа такого

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Base
{
  void Exec (void (Base::*tail)(void))
  {
    // общие действия
    ...
 
    // конкретные действия для производных классов
    // здесь уже через указатель  на метод
    (this->*tail) ();
  }
};
 
class Derived : public Base
{
  void MyExec (void)
  {
    // Выполняем основные действия с двумя разными типами
    // частных действий. Необходимую операцию преобразования
    // указателя на метод опускаю, чтобы глаза не резало
    Exec (Tail1);
    Exec (Tail2);
  }
 
  void Tail1 (void)
  {
    // Определяем конкретные действия "вариант1" для нашего класса
  }
 
  void Tail2 (void)
  {
    // Определяем конкретные действия "вариант2" для нашего класса
  }
}
Собственно вопрос: насколько опасным является преобразование указателя на метод в данном случае. Опасность не столько в преобразовании указателя на метод, сколько в том, что при вызове Derived-метода через указатель на класс Base может прийти кривой this. Понятно, что в случае "простого" наследования ничего страшного нет. Будет ли что-то криво работать в случае множественных или виртуальных наследований или в каких-то ещё тяжёлых случаев. Или такой способ при некоторых ограничениях на тип наследования можно считать надёжным и корректным? Можно ли как-то сделать статический контроль в случаях, когда такой вариант оказывается некорректным?
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
20.11.2010, 12:33
Ответы с готовыми решениями:

Вызов виртуального метода базового класса из указателя производного
Допустим есть такой код: #include <iostream> class Base { public: virtual void f() {...

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

Использовать метод transform() вместо метода sort()
Добрый день , надо исправить код , заменив метод sort() , методом transform(), не могу уловить...

Как сделать функцию от указателя на класс и указателя на метод?
Не получается сделать функцию, параметрами которой являются указатель на класс и на метод....

45
Делаю внезапно и красиво
Эксперт С++
1309 / 1224 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
16.04.2011, 14:55 21
А так нельзя?
C++
1
2
3
4
5
6
7
8
9
10
11
 void MyExec (void)
  {
    // Выполняем основные действия с двумя разными типами
    // частных действий. Вызов сути эквивалентен
    // "Exec (&this->Tail1)" и в closure-указатель копируется
    // this и адрес метода Tail1
    Exec ();
    Tail1();
    Exec ();
    Tail2();
  }
Или так?
C++
1
2
3
4
5
 void Tail1 (void)
  {
     Exec();
    // Определяем конкретные действия "вариант1" для нашего класса
  }
0
Evg
Эксперт CАвтор FAQ
21117 / 8133 / 628
Регистрация: 30.03.2009
Сообщений: 22,447
Записей в блоге: 30
16.04.2011, 15:30  [ТС] 22
Цитата Сообщение от Deviaphan Посмотреть сообщение
А так нельзя?
Конечно можно. Можно и функцией qsort не пользоваться, чтобы не работать с указателем на функцию, а ручками написать сортировку. Классом std::string тоже можно не пользоваться, а пользоваться malloc'ами и всё делать ручками. И так и так будет работать, только в одном случае интерфейсами пользоваться удобно и программу развивать несложно, а в другом - нет
0
Делаю внезапно и красиво
Эксперт С++
1309 / 1224 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
16.04.2011, 16:03 23
Цитата Сообщение от Deviaphan Посмотреть сообщение
Или так?
Сложность вызова даже уменьшится, т.к. вместо передачи параметра, будет "параметр" "вызываться".

Просто, не совсем ясна суть манипуляций, но тебе виднее, конечно, продолжай извращаться.)
0
Evg
Эксперт CАвтор FAQ
21117 / 8133 / 628
Регистрация: 30.03.2009
Сообщений: 22,447
Записей в блоге: 30
16.04.2011, 17:14  [ТС] 24
Цитата Сообщение от Deviaphan Посмотреть сообщение
Просто, не совсем ясна суть манипуляций, но тебе виднее, конечно, продолжай извращаться.)
Мне кажется, что называть что-то извращением только потому, что ты чего-то не понял - это не правильно.

Общая постановка задачи. Есть чёрный ящик, в этот чёрный ящик надо отдать пару "указатель на экземпляр + указатель на метод". Вариант с классами Basi и Dervied я привёл условно, чтобы можно было описать пример того, что именно хочется сделать через указатель на метод. Для моего примера конечно же можно сделать вызов Exec, а потом вызов Tail1. Только это для упрощённой модели можно так просто сделать. Расширенный вариант выглядит так: в метод Exec тащится __closure-указатель (который есть пара "указатель на экземпляр + указатель на метод"). Внутри метода Exec создаётся поток, в потоке запускается программа, написанная на Lua, в неё передаётся моя пара, транзитно пролетает через коды на Lua и "внизу" вызывает код на Си++, который делает вызов через эту пару.

Зачем так сложно? Любую сложный интерфейс, который взаимодействует с пользователем, можно написать двумя способами. Первый способ заключается в том, чтобы реализацию интерфейса сделать простой, сам интерфейс не очень удобный для пользователя и переложить все свои проблемы на плечи пользователя. Второй способ заключается в том, что реализацию интерфейса сделать сложной, но при этом получив простой интерфейс, который будет удобным в использовании. Я всегда иду по второму пути (если это возможно)

Пример неудобного в использовании интерфейса: борландовский класс TThread. Чтобы им пользоваться. надо определить свой класс, который является производным классом от TThread, переопределить метод Execute, реализовать событие OnTerminate, в своём основном классе обеспечить возможность для доступа ко внутренним данным и методам (потому что часть, исполняемая в потоке, реализована в другом классе). Для маленькой программы конечно же это всё сойдёт, но когда пишешь что-то большое - то разводится очень много мусора вокруг создания потока. Оговорюсь сразу, что это не претензия к борланду: этот класс является лишь некоторым классом низкого уровня, над которым пользователь будет строить обёртку, удобную в конкретной программе. Просто пытался показать пример неудобного интерфейса и как его сделать удобным

Удобным в использовании была бы надстройка над таким интерфейсом. К нашему классу (с которым мы работаем и который будет рожать поток) нам нужно добавить в родители некий базовый класс, а в момент рождения потока дёрнуть метод с прототипом типа "StartThread (f1, f2)", где f1 - это указатель на метод, который будет запущен при старте потока, f2 - указатель на метод, который будет запущен в главном процессе после завершения потока. Такой интерфейс очевидным образом использовать намного удобнее
0
Делаю внезапно и красиво
Эксперт С++
1309 / 1224 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
16.04.2011, 17:23 25
Про "извращённость" я сказал из-за того, что ты там выше писал, что тип не известен. В (почти строго) типизированном языке избавляться от типов лично мне кажется извращением.)
Этот код делает то же самое, но без каких либо вопросов:
C++
1
2
3
4
5
 void Tail1 (void)
  {
     Exec();
    // Определяем конкретные действия "вариант1" для нашего класса
  }
Собственно и для использования это проще
C++
1
2
3
4
5
A a;
a.Exec( A::Tail );
 
B b;
a.Tail();
0
Evg
Эксперт CАвтор FAQ
21117 / 8133 / 628
Регистрация: 30.03.2009
Сообщений: 22,447
Записей в блоге: 30
16.04.2011, 17:41  [ТС] 26
Цитата Сообщение от Deviaphan Посмотреть сообщение
В (почти строго) типизированном языке избавляться от типов лично мне кажется извращением.)
В "(почти строго) типизированном языке" НЕ избавляться от типов можно только путём раздувания кода (что мы и имеем на примере шаблонов Си++). И больше никак. Дополнительным побочным эффектом является то, что нет никакой возможности спрятать код.

Цитата Сообщение от Deviaphan Посмотреть сообщение
Собственно и для использования это проще
Поставлю более конкретную постановку задачи. Вот такой схематичный код:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
void BlackBox (void *this, void (*method)(void))
{
  ...
}
 
class A
{
  ...
  void func1 (void);
  void func2 (void);
};
 
class B
{
  ...
  void func1 (void);
  void func2 (void);
};
 
...
A a;
B b;
 
// Нужно, чтобы в конечном итоге как бы вызвалось a.func1()
BlackBox (&a, &A::func1);
 
// Нужно, чтобы в конечном итоге как бы вызвалось a.func2()
BlackBox (&a, &A::func2);
 
// Нужно, чтобы в конечном итоге как бы вызвалось b.func1()
BlackBox (&b, &B::func1);
 
// Нужно, чтобы в конечном итоге как бы вызвалось b.func2()
BlackBox (&b, &B::func2);
...
Напиши внутренности "чёрного ящика", чтобы вызовы BlackBox соответствовали тому, что написано в комментариях перед вызовами. Особо подчёркаваю: BlackBox НЕ является шаблоном
0
Делаю внезапно и красиво
Эксперт С++
1309 / 1224 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
16.04.2011, 18:08 27
C++
1
2
3
4
5
 void func1 (void)
{
        BlackBox( this );
        ...
}
Причём, BlackBox можно сделать полем объекта. Т.е. будет простой указатель на функцию.
0
Evg
Эксперт CАвтор FAQ
21117 / 8133 / 628
Регистрация: 30.03.2009
Сообщений: 22,447
Записей в блоге: 30
16.04.2011, 18:10  [ТС] 28
В задаче вообще-то требуется написать внутренности функции BlackBox, а не метода func1
0
Делаю внезапно и красиво
Эксперт С++
1309 / 1224 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
16.04.2011, 18:20 29
Тебе же нужно после выполнения blackbox выполнить func?
При этом тип объекта неизвестен (через void*)?
Как ты будешь выполнять какую-либо работу в blackbox, если тебе не известен тип объекта?
Всё что ты сможешь сделать, это вызвать переданный метод func.
Вот потому и непонятно мне ничего.(

Цитата Сообщение от Evg Посмотреть сообщение
вообще-то требуется написать внутренности функции BlackBox
Чёрный ящик не пишут, его используют.)
0
Evg
Эксперт CАвтор FAQ
21117 / 8133 / 628
Регистрация: 30.03.2009
Сообщений: 22,447
Записей в блоге: 30
16.04.2011, 18:27  [ТС] 30
Цитата Сообщение от Deviaphan Посмотреть сообщение
Тебе же нужно после выполнения blackbox выполнить func?
Не после, а во время

Цитата Сообщение от Deviaphan Посмотреть сообщение
Как ты будешь выполнять какую-либо работу в blackbox, если тебе не известен тип объекта?
Я же несколько раз писал, что внутри чёрного ящика я не буду выполнять работу над объектом. Я этот указатель транзитно передаю и в какой-то момент внутри этого чёрного ящика вызовется переданный метод для переданного экземпляра. Но напрямую работать с экземпляром внутри чёрного ящика я не буду

Цитата Сообщение от Deviaphan Посмотреть сообщение
Всё что ты сможешь сделать, это вызвать переданный метод func
А кроме этого от тебя ничего и не требуется в той задаче. Только вызвать метод надо не напрямую, а из BlackBox'а
0
Делаю внезапно и красиво
Эксперт С++
1309 / 1224 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
16.04.2011, 18:41 31
Цитата Сообщение от Evg Посмотреть сообщение
А кроме этого от тебя ничего и не требуется в той задаче. Только вызвать метод надо не напрямую, а из BlackBox'а
Вообще никаких проблем тогда нет. Но функтор нужен полиморфный. Дочерние классы в виде шаблона. Это будет самым правильным и типизированным.)

Добавлено через 2 минуты
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Base
{
public:
       virtual void Exec() = 0;
};
 
template<class T>
class Functor : public Base
{
public:
      T * obj;
      void Exec()
      {
           obj->func1();
      }
};
И специализировать метод ничто не мешает.
0
Evg
Эксперт CАвтор FAQ
21117 / 8133 / 628
Регистрация: 30.03.2009
Сообщений: 22,447
Записей в блоге: 30
16.04.2011, 18:42  [ТС] 32
Цитата Сообщение от Deviaphan Посмотреть сообщение
Вообще никаких проблем тогда нет. Но функтор нужен полиморфный. Дочерние классы в виде шаблона. Это будет самым правильным и типизированным.)
Ты не умничай а ответь на поставленный выше вопрос: как реализовать внутренности BlackBox без шаблонов, дополнительных классов и прочих плясок с бубнами
0
Делаю внезапно и красиво
Эксперт С++
1309 / 1224 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
16.04.2011, 19:10 33
В дополнение к коду выше
C++
1
2
3
4
5
6
7
8
9
10
11
12
void BlackBox( Base * ptr )
{
     // какой-то код
     ptr->Exec();
}
 
// Какой-то класс с методом func1.
class MyClass;
 
MyClass a;
Functor<MyClass> f;
BlackBox(&f );
Добавлено через 46 секунд
внутренности BlackBox без шаблонов, дополнительных классов и прочих плясок с бубнами
Все пляски вокруг него. И никаких бубнов. Всё логично и просто.
0
Evg
Эксперт CАвтор FAQ
21117 / 8133 / 628
Регистрация: 30.03.2009
Сообщений: 22,447
Записей в блоге: 30
16.04.2011, 23:00  [ТС] 34
Цитата Сообщение от Deviaphan Посмотреть сообщение
внутренности BlackBox без шаблонов, дополнительных классов и прочих плясок с бубнами
Какой нафиг класс Base? Какой метод Exec? Внимательно смотри пост #26 - там написаны класс A и класс B. Более того, BlackBox - это библиотечная функция, которая вообще ни о каких пользовательских классах не знает. А классы A и B - пользовательские
0
В астрале
Эксперт С++
8022 / 4779 / 654
Регистрация: 24.06.2010
Сообщений: 10,557
16.04.2011, 23:50 35
Evg, Используя расширения языка для конкретного компилятора писать код - плохая затея. Если тебе нужен только borland то и не парься, используй closure.
0
Делаю внезапно и красиво
Эксперт С++
1309 / 1224 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
17.04.2011, 07:32 36
Цитата Сообщение от Evg Посмотреть сообщение
Внимательно смотри пост #26 - там написаны класс A и класс B
Класс Base является базовым не для A и B, а для функтора. Иерархия A и B и прочих не изменяется. Раз BlackBox пишешь ты, то ничто не мешает заменить void* на Base*. Плюс ты получаешь бонус в виде возможности использовать различные типы и количество параметров для вызывемой метода и вызов более одного метода класса.
Библиотека ничего о пользовательских классах знать не будет, она будет знать только об интерфейсе функтора Base и всё.

Добавлено через 53 секунды
Я не стал писать код инициализации функтора, там просто присваивание адреса...
0
Модератор
Эксперт по электронике
8229 / 6096 / 814
Регистрация: 14.02.2011
Сообщений: 21,163
17.04.2011, 08:26 37
Evg,
еще раз повтори(много написано запутался)
чем тебя не устраивает Callback?
для таких вещей по моему он и создан.
что значит неправильный this?
Не тот класс? Не тот экземпляр?

и чем не устраивают Мессаги?
0
Evg
Эксперт CАвтор FAQ
21117 / 8133 / 628
Регистрация: 30.03.2009
Сообщений: 22,447
Записей в блоге: 30
17.04.2011, 10:13  [ТС] 38
Цитата Сообщение от ForEveR Посмотреть сообщение
Evg, Используя расширения языка для конкретного компилятора писать код - плохая затея
Расширение используется только на входе и выходе цепочки. Эти классы так или иначе являются компонентами VCL. А в серединке делается транзитная передача данных, которая от расширений языка не зависит (т.е. ей дали какой-то набор байтов, и этот набор просто скопировался)

Цитата Сообщение от ForEveR Посмотреть сообщение
Если тебе нужен только borland то и не парься, используй closure.
Я не парюсь. Человек не понял, а я ему объясняю. Причём объясняю не решение, а поставленный вопрос.

Цитата Сообщение от Deviaphan Посмотреть сообщение
Класс Base является базовым не для A и B, а для функтора. Иерархия A и B и прочих не изменяется. Раз BlackBox пишешь ты, то ничто не мешает заменить void* на Base*. Плюс ты получаешь бонус в виде возможности использовать различные типы и количество параметров для вызывемой метода и вызов более одного метода класса.
Библиотека ничего о пользовательских классах знать не будет, она будет знать только об интерфейсе функтора Base и всё.
Ты напиши исходник хотя бы схематично, а не на словах объясняй. И, как я уже неоднократно объяснял, сделай это без шаблонов

Цитата Сообщение от ValeryS Посмотреть сообщение
Evg,
еще раз повтори(много написано запутался)
чем тебя не устраивает Callback?
для таких вещей по моему он и создан.
что значит неправильный this?
Не тот класс? Не тот экземпляр?

и чем не устраивают Мессаги?
Может я плохо выразился. Заставить свои коды работать я могу всегда. И всегда могу придумать с десяток решений: от идиотских до черезж...ых. В данном случае я пытаюсь найти решение, которое было бы максимально удобным для пользователя.

Давай вернёмся к примеру из последнего абзаца поста #24. Постановка задачи, например, такая. Пользователь пишет класс окна (TForm). Нужно скачать из инета картинку и отобразить её на форме. Если скачивание выполнять в главном процессе, то в момент скачивания приложение будет "висеть": т.е. оно никак не будет реагировать на нажатия кнопок, не будет перерисовываться если поверх него протащить другое окно и т.п. Чтобы этого избежать, надо процесс скачивания утащить в поток. Пока картинка скачивается в потоке, приложение живёт своей жизнью: реагирует на нажатия на кнопочки, менюшки и прочие события. Как только картинка скачалась, то главный процесс каким-то образом об этом узнает и вызовет код, который отрисует картинку на форму (потому что из потока рисовать нельзя). Как такой набор действий сделать максимально удобным для пользователя? У меня работает следующий вариант. Всё то, что начинается с User - это то, что пишет пользователь, а с Lib - это библиотека. Схематично:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class UserForm : public LibForm
{
  ...
 
  void UserGetImage (void)
  {
    LibStartThread (UserDownloadImage, UserDisplayImage);
  }
 
  void UserDownloadImage (void)
  {
    // Скачивание картинки (в потоке)
  }
 
  void UserDisplayImage (void)
  {
    // Отрисовка картинки (в главном процессе)
  }
}
Т.е. для того, чтобы работать с потоками, пользователю необходимо всего два дополнительных действия, которые являются максимально примитивными: добавить в родителя класс LibForm и поставить вызов библиотечного метода LibStartThread, подав параметрами указатели на собственные методы UserDownloadImage и UserDisplayImage. Эти два собственных метода так или иначе пришлось бы реализовывать, а потому они практически не являются дополнительными действиями. Каким образом библиотечный метод LibStartThread обеспечит вызов UserDownloadImage в потоке, дальнейший выход из себя (т.е. после запуска потока работа UserGetImage завершится и приложение начнёт обрабатывать сообщения) и вызов UserDisplayImage в главном процессе после завершения работы потока - это исключительно проблема библиотеки и пользователя она никоим боком не колышет. И речь об этом сейчас не идёт. Речь идёт только о том, каким образом организовать максимально удобный для пользователя интерфейс (разумеется, в пределах того, что позволяет язык)

Если ты можешь предложить что-то более удобное для пользователя (а не для того, кто будет библиотеку поддержки реализовывать) - предложи

Добавлено через 44 секунды
И заодно объясни, что такое Callback

Добавлено через 10 минут
Да, вот ещё. Библиотека поддерживает возможность работы без потока. Т.е. LibStartThread может запустить UserDownloadImage и UserDisplayImage последовательно в главном процессе - сие удобно для процесса отладки, если возникает подозрение, что проблема обусловлена работой с потоком. Переключение между двумя режимами опять-таки делается одним лёгким движением руки
0
Делаю внезапно и красиво
Эксперт С++
1309 / 1224 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
17.04.2011, 10:40 39
Цитата Сообщение от Evg Посмотреть сообщение
напиши исходник хотя бы схематично, а не на словах объясняй. И, как я уже неоднократно объяснял, сделай это без шаблонов
Я полностью исходник написал уже.) Шаблоны только для уменьшения ручного кодирования, BlackBox работает без шаблонов, т.е. с выносом в библиотеку трудностей не будет.
Я повторю код.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// Интерфейс функтора. Ничего не знает о классах A,B и любых других.
class FunctorBase
{ public:
        virtual void Execute() = 0;
};
 
// Никаких шаблонов нету.
void BlackBox( FunctorBase * f )
{
        // Твой код
        // Под конец выполняем функтор
        f->Execute();
}
 
// другой файл/модуль/пофиг
// 
template<class T>
class Functor : public FunctorBase
{
public:
      Functor( T * t )
      : obj(t)
      {}
 
      void Execute()
      {
            obj->func1();
      }
 
       T * obj;
};
 
// Пользовательские классы. Ничего не знают о FunctorBase и Functor  и BlackBox
class A
{
public:
      void func1();
};
class B;
class C
{
public:
         void func1();
         void func2();
};
 
template<>
void Functor<C>::Execute()
{
     obj->func1();
     obj->func2();
}
 
void main()
{
      A a;
      B b;
      C c;
 
      Functor<A> fa(&a);
      Functor<B> fb(&b);
      Functor<C> fc(&c);
 
      BlackBox( &fa );
      BlackBox( &fb );
      BlackBox( &fc );
 
}
Добавлено через 1 минуту
Если в BlackBox передавать по ссылке, то ещё проще код сделать можно.

Добавлено через 2 минуты
Шаблоны используются только в пользовательском коде и можно обойтись без них. Это просто облегчение жизни пользователю. BlackBox шаблоны не использует.
0
Evg
Эксперт CАвтор FAQ
21117 / 8133 / 628
Регистрация: 30.03.2009
Сообщений: 22,447
Записей в блоге: 30
17.04.2011, 11:11  [ТС] 40
Deviaphan, вот сравни твой код (пост 39) и мой (пост 38). В моём случае дополнительных действий раз-два и обчёлся, а в твоём случае пользователю надо писать кучу дополнительного кода. В твоём коде нет раздельного запуска двух методов по отдельности (т.е. ты в методе Execute запускаешь их одновременно). Чтобы обеспечить раздельный запуск методов, тебе придётся описывать два пользовательских класса Functor. Не говоря уж о том, что пользователь при таком раскладе свои методы ОБЯЗАН называть func1 и func2 (в противном случае работать не будет). Т.е. твой способ подразумевает перекладывание большого количества проблем с автора библиотеки на пользователя библиотеки.

Добавлено через 9 минут
Цитата Сообщение от Evg Посмотреть сообщение
что пользователь при таком раскладе свои методы ОБЯЗАН называть func1 и func2
Либо для каждого имени метода создавать ещё один шаблон
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
17.04.2011, 11:11

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь.

Переопределение виртуального метода
Нужно написать виртуальный метод в родительском классе , который находит площадь круга. Затем...

переопределение виртуального метода
Существует родитель-класс TEditField = class(TObject) protected procedure...

Ошибка создания виртуального метода?
Здравствуйте, хочу сделать так что бы программа(на андроид) рисовала по заданным координатам, но...

Реализовать перегрузку виртуального метода
В класе class1 реализован открытый виртуальный метод деление двух чисел &quot;a&quot; и &quot;b&quot;. Не внося...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2020, vBulletin Solutions, Inc.