Каким должен быть С++?
, Ваше мнение
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
| ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
| [216.73.216.156] |
|
|
Правила раздела:
| Страницы: (6) « Первая ... 3 4 [5] 6 все ( Перейти к последнему сообщению ) |
Каким должен быть С++?
, Ваше мнение
|
Сообщ.
#61
,
|
|
|
|
Это не всегда возможно. Каким образом процедура test может получить фактический класс значения переменной x из статической информации о ней? |
|
Сообщ.
#62
,
|
|
|
|
Цитата korvin @ Это не всегда возможно. Каким образом процедура test может получить фактический класс значения переменной x из статической информации о ней? Да, возможностей меньше, но рефлексия во время исполнения слабо вяжется с нишей языка. Если они так сильно нужны, то можно взять другой язык. Ну, а test в данном случае можно сделать шаблоном. |
|
Сообщ.
#63
,
|
|
|
|
Цитата MyNameIsIgor @ Ну, а test в данном случае можно сделать шаблоном Каким образом это поможет, если я захочу применить ее (в цикле) к коллекции [Parent*], в которой могут находиться элементы любого дочернего класса? По-моему было бы неплохо иметь возможность создавать (локальные, временные) расширения классов без необходимости в рантайме создавать копию коллекции (в отличие от использования субклассов), типа того: ![]() ![]() extension Test { class Parent { public: virtual void describe() { ^describe(); // вызов оригинального метода Parent::describe cout << " extension Test"; } }; class Child { public: virtual void describe() { cout << "Child extension Test"; } }; }; void test(vector<Parent> xs) { extend xs : Test; for (auto x : xs) { x->describe(); cout << endl; } } Только я не представляю как это можно (или насколько сложно) сделать потокобезопасно. |
|
Сообщ.
#64
,
|
|
|
|
Цитата korvin @ Каким образом это поможет, если я захочу применить ее (в цикле) к коллекции [Parent*], в которой могут находиться элементы любого дочернего класса? В случае run-time созданной коллекции, конечно, никаким. Но с помощью статической рефлексии можно сгенерировать информацию, которая будет использовать во время исполнения. Это потребует лишних телодвижений от программиста со всякой регистрацией и тому подобным, но лучше соответствует духу языка. Цитата korvin @ По-моему было бы неплохо иметь возможность создавать (локальные, временные) расширения классов без необходимости в рантайме создавать копию коллекции (в отличие от использования субклассов), типа того: Должен сказать, что не осилил что это и о чём ты хочешь сказать :-) |
|
Сообщ.
#66
,
|
|
|
|
Цитата MyNameIsIgor @ Должен сказать, что не осилил что это и о чём ты хочешь сказать :-) Ну вот смотри, вернемся к цели использования рефлексии, допустим в примере с test это могло бы быть что-то вроде: ![]() ![]() class Parent { public: virtual void describe() { cout << "Parent"; } }; class Child : public Parent { public: virtual void prefix() { cout << "\t"; } virtual void describe() { cout << "Child"; } }; void test(Parent *x) { // синтаксис условный if (RTTI::supports(x, RTTI::class<Child>())) RTTI::cast<Child>(x)->prefix(); x->describe(); cout << endl; } что с точки зрения ООП как бы не очень хорошо, ведь для такого и существуют классы (точнее ad-hoc полиморфизм и data directed programming), чтобы специализированный код выбирался автоматически по типу данных без всяких if'ов. Вообще более общий случай -- проверка наличия метода void prefix(), но не будем усложнять. Можно создать субкласс Child ![]() ![]() class ChildExt : public Child { public: virtual void describe() { prefix(); Child::describe(&this); } }; или прокси ![]() ![]() class ChildProxy : public Child { private: Child *original; public: virtual void describe() { original->prefix(); original->describe(); } virtual Child* getOriginal() { return original; } }; но тут есть проблемы: нужно правильно найти места для преобразования (мы не можем преобразовать коллекцию, т.к. там уже статическая информация потеряна и мы возвращаемся к RTTI), нужно как-то вернуть все обратно, ведь преобразованные элементы скорее всего необходимо передавать дальше. Плюс накладные расходы на все это в рантайме. Вот если бы мы могли локально, временно изменять классы, не затрагивая сами объекты, тогда бы все эти проблемы были бы решены. ![]() ![]() extension Test { class Child { public: virtual void describe() { prefix(); ^descibe(); // original } } }; Тогда бы test осталась бы максимально простой, никаких "дум" где и как вставить преобразование объектов Child к ChildExt или ChildProxy, почти никаких накладных расходов на рантайм ![]() ![]() void test(Parent *x) { x->describe(); cout << endl; } ... extend Test; // область действия определяется как и для всего остального -- по области видимости for (Parent *x : xs) test(x); ... Вообще это похоже на динамические переменные CL, только применяется к классам. |
|
Сообщ.
#67
,
|
|
|
|
Я попробовал. Два полиморфных вызова на каждый позднесвязываемый параметр. Думаю, ещё эффективнее не выйдет.
Добавлено Ладно, будет сам мой дембельский аккорд. Всё равно за три дня не успею под C++11 перенести, раз до сих пор так и не собрался. А скоро уже и не надо будет, ибо будут испаропки. |
|
Сообщ.
#68
,
|
|
|
|
Исправил. Добавлено Цитата Qraizer @ Я попробовал. Два полиморфных вызова на каждый позднесвязываемый параметр. Думаю, ещё эффективнее не выйдет. Я помню их - там необходима регистрация в одном месте, что неприемлемо. Это во-первых. Во-вторых, если мы оставляем подобную регистрацию, то эффективнее можно по тому же принципу, что описан у Страуструпа. |
|
Сообщ.
#69
,
|
|
|
|
Эффективнее можно при поддержке языка. Я говорил о библиотеке.
|
|
Сообщ.
#70
,
|
|
|
|
Цитата Qraizer @ Эффективнее можно при поддержке языка. Я говорил о библиотеке. Я тоже. Таблицу, про которую пишет Бьярн, можно сформировать, если регистрация всего происходит в одном месте. |
|
Сообщ.
#71
,
|
|
|
|
korvin, правильно ли я понимаю, что таким "расширением класса" ты в данном случае говоришь "для всех Child в этой коллекции вызови prefix перед describe"?
|
|
Сообщ.
#72
,
|
|
|
|
Цитата MyNameIsIgor @ правильно ли я понимаю, что таким "расширением класса" ты в данном случае говоришь "для всех Child в этой коллекции вызови prefix перед describe"? Да. |
|
Сообщ.
#73
,
|
|
|
|
Цитата korvin @ Цитата MyNameIsIgor @ правильно ли я понимаю, что таким "расширением класса" ты в данном случае говоришь "для всех Child в этой коллекции вызови prefix перед describe"? Да. Ну, тогда это возможно реализовать. По семантике это как раз предложение от Страуструпа и Ко по мультиметодам ![]() ![]() ![]() void test(virtual Parent* p) { p->describe(); } void test(virtual Child* p) { p->prefix(); p->describe(); } for(Parent* p : vector) test(p); Конечно, решить общий случай проверки наличия метода с заданным именем и сигнатурой это не позволяет. |
|
Сообщ.
#74
,
|
|
|
|
Цитата MyNameIsIgor @ По семантике это как раз предложение от Страуструпа и Ко по мультиметодам Да, думаю, так лучше. Цитата MyNameIsIgor @ Конечно, решить общий случай проверки наличия метода с заданным именем и сигнатурой это не позволяет. Ну, мой огород этого тоже не позволяет, но само по себе решение этой небольшой проблемы с test покрывает 99% случаев использования рантайм-рефлексии, ИМХО. Добавлено Вообще для упрощения можно было бы ограничиться для начала не мультиметодами, а просто "внешними" методы. |
|
Сообщ.
#75
,
|
|
|
|
Цитата korvin @ Вообще для упрощения можно было бы ограничиться для начала не мультиметодами, а просто "внешними" методы. Имеешь в виду возможность добавления в класс методов без его изменения? Типа этого? Просто это рассматривается как изменение на уровне синтаксиса. А документ по мультиметодам скорее сосредоточен на способе их реализации, и для одного параметра вызов foo(bar) полностью эквивалентен существующим виртуальным методам bar.foo() |