|
|
|
Вызвать метод наследника, если известно что этот метод точно есть
|
|||
|---|---|---|---|
|
#18+
Если программист пишет в коде: Y=”Print”; X[Y](); То понятно, что на этапе компиляции мы не можем определить, какой метод объекта X хочет вызвать программист, и должны искать соответствие по таблице методов. Единственное, в этой точке кода мы можем сделать хеширование, чтобы проверять, если в очередной раз название требуемого метода соответствует предыдущему, не искать, а выдавать готовый метод (например, в циклах). Но такая формулировка встречается очень редко. Обычно программист пишет: X.Print(); Тогда можно завести глобальный двумерный массив, где перечислены все методы (Print, Copy, Paste, Run и т.д….) для всех классов. Каждый экземпляр класса (например в Delphy) обычно содержит информацию о своем типе, поэтому можно обратиться к этому двумерному массиву и определить, по какому адресу расположен нужный метод у нужного объекта. Если метода нет, можно в этой двумерной таблице проставлять ссылку на метод NoMethod соответствующего класса – метод, который обрабатывает случай, когда запрашивают метод, которого нет (чтобы не вводить дополнительную проверку, существует ли сооветствующий метод у класса). Пример: class Basic { function NoMethod() {return false;} }; class Printable:Basic { function Print(Msg) { ... ; return true;} } class NoPrintable:Basic { function Calculate() {} } function test(X:Basic) { return X.print("Hello"); //Должно замениться на ClassesMethods[GetType(X)][CONST_PRINT] (“Hello”); } a=new Printable; //print есть b=new NoPrintable; //printа нет r1=test(a); //вернется true r2=test(b); //вернется false Переформулируем вопрос по другому: Пусть есть некий класс Printable, наследующий от Basic, у него есть некий метод Print(Msg:Basic). В переменной X хранится экземпляр типа Printable. function test(X:Basic, T){ (X as X.GetType()).Print(“Hello”); } Компилятор какого языка позволяет скомпилировать код так, чтобы на этапе выполнения можно было динамически преобразовать X к другому, заранее неизвестному типу X.GetType()? Ведь на этапе выполнения я знаю адрес метода Printable::Print, остается только вызвать, так почему я не могу этого сделать? В принципе, в С++ наверное можно получить явный указатель на любой метод любого класса (или это не так?): FunctionPointer=X.GetType()::Print; * FunctionPointer (“Hello”); Единственное, нужно, чтобы локальные переменные очищала не функция, а точка вызова функции, чтобы не запутаться в количестве локальных переменных. По сути, вопрос сводится к тому, как вызвать из модуля какого-то постороннего кода метод наследника, если заранее неизвестно, какой из наследников базового класса будет передан на вход этого модуля. IDispatch не предлагать, вопрос, думается, можно разрешить проще, например написанием препроцессора для кода. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 05.03.2007, 18:32 |
|
||
|
Вызвать метод наследника, если известно что этот метод точно есть
|
|||
|---|---|---|---|
|
#18+
Адептов жабы просьба не смущать молодые умы!!! --- Если молния в лоб попадет, Значит просто подставлен лоб ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 05.03.2007, 19:34 |
|
||
|
Вызвать метод наследника, если известно что этот метод точно есть
|
|||
|---|---|---|---|
|
#18+
ИМХО Dispatch как раз для такого и сделан ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 05.03.2007, 19:37 |
|
||
|
Вызвать метод наследника, если известно что этот метод точно есть
|
|||
|---|---|---|---|
|
#18+
Можно и без диспатч обойтись, теоретически, вопрос как это сделать практически. Да, джаву не предлагать. В С++ ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 05.03.2007, 20:14 |
|
||
|
Вызвать метод наследника, если известно что этот метод точно есть
|
|||
|---|---|---|---|
|
#18+
Предлагаемая схема Будем рассматривать только методы (со свойствами будем поступать идентично). Обычно в компиляторах метод M класса A имеет фиксированное расположение (адрес) в памяти, т.е. имеется ссылка на метод A::М. Если мы хотим динамически добавлять/удалять классы, то должен существовать некоторый массив классов Сlasses. Каждый класс имеет свойство ClassNo, которое определяет под каким индексом в массиве Classes хранится описание этого класса. Это свойство устанавливается после добавления нового класса в массив классов. Каждое описание классов содержит массив Methods следующей структуры: название метода, адрес метода. Этот массив служит для быстрого определения адреса метода по его названию. Массив обычно упорядочен по названию метода для ускорения поиска адреса метода. Каждый класс содержит статический (существующий в единственном экземпляре на все экземпляры класса) массив методов LocalMethods (но не методов класса, а вообще). Анализируются все вызовы методов в коде класса, к ним добавляются названия методов самого класса. Названия всех методов заносятся в массив LocalMethods. А вызовы методов заменяются на вызов функции CallMethod, например: O.Method(P1, .., PN) заменяется на CallMethod (O, 10) (P1..PN), где 10 – номер метода Method в массиве LocalMethods. Функция CallMethod(Object, MethodNo) имеет такой код: Addr=Classes(Object.ClassNo, MethodNo); If Addr=0 Then Addr=Find() Classes(Object.ClassNo, MethodNo)= End if Return Addr Эта функция возвращает адрес, по которому расположен метод Method объекта Object и затем вызывает этот метод с параметрами. Таким образом, поиск адреса метода осуществляется только при первом вызове. Не нужно даже сразу рассчитывать адреса для всех элементов массива LocalMethods. Если же метод вызывается по имени (динамическое связывание), поиск осуществляется в массиве Methods, но так как в этой таблице методы не отсортированы (для сохранения порядка), то используется вспомогательный глобальный массив индекса MethodsIndex. Каждый объект имеет метод NoMethod, который вызывается, если у объекта нет запрашиваемого метода. Ссылка на этот метод проставляется для всех методов, которых нет у класса в массиве Classes. Приведем пример: Class A LocalMethods: X: 1 Y: 2 Z: 3 LocalClasses: B: 2 C: 3 Function X() O1=New “B” O1.Z() Function Y() O2=New “B” O2.Z() O2.X() O3=New “C” O3.Y() Class B() LocalMethods: X: 1 Y: 2 Z: 3 LocalClasses: A: 1 B: 2 C: 3 Function Z() O4=New “A” O4.X() Function X() O5=New “B” O5.() O5.X() O6=New “C” O6.Y() Class C() LocalMethods: Y: 2 Z: 3 LocalClasses: A: 1 B: 2 Function Y() O1=New “B” O1.Z() Function Z() O1=New “A” O1.Z() O1.X() Classes: 1. A o X A::X o Y A::Y o Z A::NoMethod 2. B o X B::X o Y B::NoMethod o Z A::Z 3. C o X C::NoMethod o Y C::Y o Z C::Z Понятно, что схему раздельной компиляции классов можно развить и для наследуемых классов, т.е. отдельно компилировать базовый и наследующий от него класс. В таком случае при загрузке наследуемого класса нужно только заменить в виртуальной таблице методов ссылку на метод родителя реальным адресом этого родителя. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 05.03.2007, 20:20 |
|
||
|
Вызвать метод наследника, если известно что этот метод точно есть
|
|||
|---|---|---|---|
|
#18+
Извините за вопрос а зачем это все? Ну слабаешь ты такую таблицу с метаданными( ну присовокупи сюда проблемы с перегрузкой и множественным наследованием). Что с ней делать? Тут же станет вопрос о том какие параметры в метод класса можно передавать, какие нельзя. Правильно ли их передали и прочее. Ну не сделаешь ты reflect, да и не надо.. ---- Если молния в лоб попадет, Значит просто подставлен лоб ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 05.03.2007, 20:34 |
|
||
|
Вызвать метод наследника, если известно что этот метод точно есть
|
|||
|---|---|---|---|
|
#18+
Блиндед, надо! Чтобы не париться, если известен тип, и исзвестно что у него есть такой метод, то нужно вызвать этот метод из переменной базового типа. Нужно! ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 05.03.2007, 20:35 |
|
||
|
Вызвать метод наследника, если известно что этот метод точно есть
|
|||
|---|---|---|---|
|
#18+
Возьми и сделай dynamic_cast и не надо на меня кричать. Лучше открыть книжку ---- Если молния в лоб попадет, Значит просто подставлен лоб ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 05.03.2007, 20:40 |
|
||
|
Вызвать метод наследника, если известно что этот метод точно есть
|
|||
|---|---|---|---|
|
#18+
Fixin, "грабить ничего не надо. Все уже украдено до нас". Волшебное слово - "design patterns". Я не совсем понял че Вы точно хотите, может подойти паттерн facade (в зависимости от переданного параметра разные функции могут быть вызваны) или abstract factory , factory method паттернс.. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 05.03.2007, 20:54 |
|
||
|
Вызвать метод наследника, если известно что этот метод точно есть
|
|||
|---|---|---|---|
|
#18+
A. Fig LeeFixin, "грабить ничего не надо. Все уже украдено до нас". Волшебное слово - "design patterns". Я не совсем понял че Вы точно хотите, может подойти паттерн facade (в зависимости от переданного параметра разные функции могут быть вызваны) или abstract factory , factory method паттернс.. Ну все же понятно из примера что мне нужно: class Basic { function NoMethod() {return false;} }; class Printable:Basic { function Print(Msg) { ... ; return true;} } class NoPrintable:Basic { function Calculate() {} } function test(X:Basic) { return X.print("Hello"); //ВОТ ЗДЕСЬ НУЖНО ЧТОБЫ ВЫЗВАЛСЯ МЕТОД PRINT!!!!!!!!!!!!!!!!!!!!!!!!} a=new Printable; //print есть b=new NoPrintable; //printа нет r1=test(a); //вернется true r2=test(b); //вернется false ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 06.03.2007, 18:04 |
|
||
|
Вызвать метод наследника, если известно что этот метод точно есть
|
|||
|---|---|---|---|
|
#18+
Fixin A. Fig LeeFixin, "грабить ничего не надо. Все уже украдено до нас". Волшебное слово - "design patterns". Я не совсем понял че Вы точно хотите, может подойти паттерн facade (в зависимости от переданного параметра разные функции могут быть вызваны) или abstract factory , factory method паттернс.. Ну все же понятно из примера что мне нужно: class Basic { function NoMethod() {return false;} }; class Printable:Basic { function Print(Msg) { ... ; return true;} } class NoPrintable:Basic { function Calculate() {} } function test(X:Basic) { return X.print("Hello"); //ВОТ ЗДЕСЬ НУЖНО ЧТОБЫ ВЫЗВАЛСЯ МЕТОД PRINT!!!!!!!!!!!!!!!!!!!!!!!!} a=new Printable; //print есть b=new NoPrintable; //printа нет r1=test(a); //вернется true r2=test(b); //вернется false Ето я понял. Я не понял - зачем? Ну сделайте виртуальный метод Код: plaintext ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 06.03.2007, 18:18 |
|
||
|
Вызвать метод наследника, если известно что этот метод точно есть
|
|||
|---|---|---|---|
|
#18+
Я заранее не знаю, какие методы мне потом понадобятся, понимаете? Ну вот например, я выбираю все справочники в системе и для некоторых из них (определяю по методу-классификатору справочника) мне нужно сделать кое-какие действия. Не буду же я менять ядро на каждый чих... Вопрос прежний - как сделать то что мне нужно, не меняя ЯДРО. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 06.03.2007, 18:20 |
|
||
|
Вызвать метод наследника, если известно что этот метод точно есть
|
|||
|---|---|---|---|
|
#18+
Вопрос прежний - как сделать то что мне нужно, не меняя ЯДРО. смотря что считать ядром.. (0) если, скажем только базу, то можно наследовать листовые классы от интерфейсов типа IPrintable, а потом делать dinamic_cast<IPrintable*>() (1) если планируется устойчивая иерархия классов с последующим добавлением методов, то это шаблон Visitor (2) ну либо динамическая регистрация методов в глобальных ассоциативных структурах по идентификатору типа, что-то вроде реализации мультиметодов по пунктам 1 и 2 очень хорошо написано у Алесандреску ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 06.03.2007, 18:46 |
|
||
|
Вызвать метод наследника, если известно что этот метод точно есть
|
|||
|---|---|---|---|
|
#18+
FixinЯ заранее не знаю, какие методы мне потом понадобятся, понимаете? нет. Fixin Ну вот например, я выбираю все справочники в системе и для некоторых из них (определяю по методу-классификатору справочника) мне нужно сделать кое-какие действия. Не буду же я менять ядро на каждый чих... Вопрос прежний - как сделать то что мне нужно, не меняя ЯДРО. Вы хотите сказать, что на етапе компиляции Вам не известен не название метода, ни его параметры и их количество? facade спасет отца русской демократии. Если Вы НИЧЕГО не знаете, то Вам уже ничего не поможет. Нужен хотя бы 1 (один) метод с известными параметрами. Типа: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 06.03.2007, 18:50 |
|
||
|
Вызвать метод наследника, если известно что этот метод точно есть
|
|||
|---|---|---|---|
|
#18+
Думаю следующее: 1) В C++ "без выкрутасов" нельзя взять указатель на функцию класса, неизвестного на этапе разработки. На Delphi можно. 2) Не вижу ни одного практического применения такой конструкции... 3) Вроде бы нечто похожее можно сделать (т.е. уже реализовано) через сигналы и слоты в Qt4. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 06.03.2007, 19:20 |
|
||
|
|

start [/forum/topic.php?fid=57&msg=34375550&tid=2029315]: |
0ms |
get settings: |
9ms |
get forum list: |
12ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
165ms |
get topic data: |
9ms |
get forum data: |
2ms |
get page messages: |
47ms |
get tp. blocked users: |
1ms |
| others: | 239ms |
| total: | 490ms |

| 0 / 0 |
