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

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

ru
Offline Offline

« : 04-07-2003 04:27 » 

Подскажите кто может (пытаюсь перелезть на VC из Delphi),
как получить указатель на виртуальный метод класса в VC ?
В Delphi аналог есть, директива of object.
Явно заданный this выходом не считаю.
Заранее спасибо.
Записан

while (8==8)
Гром
Птычк. Тьфу, птычник... Вот!
Готовлюсь к пенсии

il
Offline Offline
Пол: Мужской
Бодрый птах


« Ответ #1 : 04-07-2003 06:39 » 

Давай разберемся.
Мне не очень понятно - в свете того что Дельфи я не знаю, почему тебе не подходит this и почему указатель на виртуальную функцию...

Ведь виртуальная ф-ия без тела по сути может не иметь тела и должна быть переопределена в классе наследнике. А ты требуешь указатель на что??
Записан

А птичку нашу прошу не обижать!!!
Diletant
Помогающий

de
Offline Offline

« Ответ #2 : 04-07-2003 06:55 » 

Цитата: Гром

Ведь виртуальная ф-ия без тела по сути может не иметь тела и должна быть переопределена в классе наследнике.


Чтой-то Вы, ваше величество, замысловато завернули.  Улыбаюсь  Из этой фразы вытекает, что виртуальная ф-ия без тела по сути (или без сути) может тело все-таки иметь
Записан
SlavaI
Главный специалист

ru
Offline Offline

« Ответ #3 : 04-07-2003 07:06 » 

Предположим у нас такой код

Код:
#include "stdafx.h"
#include <iostream.h>

class Base
{
public:
Base(){;};
virtual ~Base(){;};
virtual void A()=0;
};

class Derived: public Base
{
int x;
public:
virtual ~Derived(){;};
Derived():Base(),x(10){;};
virtual void A(){ cout<<this->x<<endl; };
};

int _tmain(int argc, _TCHAR* argv[])
{
Derived d,*ptrd;
d.A();
return 0;
}

как получить адрес d.A()? Так вопрос что ли стоит.
Адрес ее конечно есть, и хранится в таблице вызовов экземпляра класса, но вот как его получить не привязываясь к конкретной платформе и компилятору, то есть на чистом C++ я пока не знаю. И по моему стандарт языка такой возможности не предусматривает, так как имея адрес вызвать ее не удастся, надо еще ей передать указатель this, а это платформенно и компиляторно зависимая вещь.
« Последнее редактирование: 18-11-2007 06:16 от Алексей1153++ » Записан
Гром
Птычк. Тьфу, птычник... Вот!
Готовлюсь к пенсии

il
Offline Offline
Пол: Мужской
Бодрый птах


« Ответ #4 : 04-07-2003 07:29 » 

Цитата: Diletant
Цитата: Гром

Ведь виртуальная ф-ия без тела по сути может не иметь тела и должна быть переопределена в классе наследнике.


Чтой-то Вы, ваше величество, замысловато завернули.  Улыбаюсь  Из этой фразы вытекает, что виртуальная ф-ия без тела по сути (или без сути) может тело все-таки иметь


Да, имелось в виду, что непонятно на каком этапе нужен указатель - возможно человек просто не понял сути виртуальных функций и хочет указатель на саму виртуальную функцию Улыбаюсь без переопределения.

Слава - так то что ты сказал - для любой функции класса, не только виртуальной.

И ИМХО речь вроде идет о VC поэтому я и попросил уточнить
Записан

А птичку нашу прошу не обижать!!!
Lex
Специалист

ru
Offline Offline

WWW
« Ответ #5 : 04-07-2003 07:31 » 

Цитата

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


Истино так. может зависеть даже от версии компилятора.
Записан

Megabyte be with you!
sss
Специалист

ru
Offline Offline

« Ответ #6 : 04-07-2003 07:43 » 

Цитата: Гром
Давай разберемся.
Мне не очень понятно - в свете того что Дельфи я не знаю, почему тебе не подходит this и почему указатель на виртуальную функцию...

Ведь виртуальная ф-ия без тела по сути может не иметь тела и должна быть переопределена в классе наследнике. А ты требуешь указатель на что??


ну я в смысле не абстрактная, ....
блин, как трудно объяснить, к Дельфи привык.
Там надстройка к системе сообщений так построена. Есть переменная в родителе указывающая на функцию в его потомках(и не только).
Родитель смотрит, указатель не пустой, и вызывает метод. Это позволяет разгрузить WndProc.

Директива of object используется при описании типа.

type
       TNotifyEvent: procedure(Sender: TObject); of object;


 TBase = class
    procedure NotifyEvent(Sender: TObject); virtual; // тело должно быть
   
   // в Delphi вот так
    procedure NotifyEvent(Sender: TObject); abstract; // тела нет

 TClassA = class
    A: TNotifyEvent;
 end;

 TClassB = class(TBase)
    procedure NotifyEvent(Sender: TObject); override;
 end;

 TClassC = class(TBase)
    procedure NotifyEvent(Sender: TObject); override;
 end;

var
    P: TNotifyEvent;  //
    B: TClassB;
    C: TClassC;
begin
  ...
  P :=  B.NotifyEvent;  // метод B и self на месте
  P(nil);                        
  P :=  C.NotifyEvent;  // метод С и self на месте
  P(nil);
  ...
end;

А в VC получается только со статикой. Думал, есть стандартная заковырка в VС про которую не знаю.
Это все можно решить, если описать структуру с this и jmpptr, плюс при вызове данной функции asm включить. Так вроде asm нельзя использовать в макросах С, т.е. будет больно.

P.S: Я пока примеры на С не буду показывать, а то опозорюсь совсем
       жду ответ on-line. На выходных надо учиться, а доступа к
       Вам нет !
Записан

while (8==8)
Lex
Специалист

ru
Offline Offline

WWW
« Ответ #7 : 04-07-2003 07:52 » 

А для чего тебе это надо?
IMHO, если в цикле вызвать виртуальный метод для какого-нить массива/списка объектов, то указатель на виртуальную функцию и не нужен.
Записан

Megabyte be with you!
SlavaI
Главный специалист

ru
Offline Offline

« Ответ #8 : 04-07-2003 07:59 » 

Цитата: sss
Это все можно решить, если описать структуру с this и jmpptr, плюс при вызове данной функции asm включить. Так вроде asm нельзя использовать в макросах С, т.е. будет больно.

P.S: Я пока примеры на С не буду показывать, а то опозорюсь совсем
       жду ответ on-line. На выходных надо учиться, а доступа к
       Вам нет !


Насчет __asm никаких ограничений нет, так как макрос просто подставляется в код препроцессором. Есть только ограничение в 64 разрядных компиляторах- они __asm больше не делают, убран встроенный ассемблер.
Записан
PSD
Главный специалист

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

« Ответ #9 : 04-07-2003 08:02 » 

Я думаю(как и Слава) что ты его иначе как из таблицы вертуальных функций не получишь.
Потому как метод класса при комниляции заменяется не адресом а индексом.
И у метода класса есть скрытый параметр this


Объясни пожалуста что ты хочешь сделать?
Записан

Да да нет нет все остальное от лукавого.
sss
Специалист

ru
Offline Offline

« Ответ #10 : 04-07-2003 08:56 » 

Цитата: PSD
Я думаю(как и Слава) что ты его иначе как из таблицы вертуальных функций не получишь.
Потому как метод класса при комниляции заменяется не адресом а индексом.
И у метода класса есть скрытый параметр this


Объясни пожалуста что ты хочешь сделать?



1. Менять вызов функции динамически
2. Создавать подписи на вызов в виде очереди
3. Динамически подключать/отключать класс к классу

Вообще то идей куча, реализации есть... на дельфи   Вот такой я вот ,
Данных по VMT (как строится) нет.
Записан

while (8==8)
Гром
Птычк. Тьфу, птычник... Вот!
Готовлюсь к пенсии

il
Offline Offline
Пол: Мужской
Бодрый птах


« Ответ #11 : 04-07-2003 09:18 » 

Что- то я не совсем понимаю, что собственно надо... :?:
Цитата

1. Менять вызов функции динамически

Что сие означает - вызов функции по сообщению или прямой вызов-  и что мешает работать в case Не понял
Цитата

2. Создавать подписи на вызов в виде очереди

Это у меня вобще ассоциации вызвало только с очередями за колбасой - какие подписи???
Цитата

3. Динамически подключать/отключать класс к классу


Так это - в смысле - объявляй поинтер и конструируй класс и дестрой его сколько влезет Не понял
Записан

А птичку нашу прошу не обижать!!!
Diletant
Помогающий

de
Offline Offline

« Ответ #12 : 04-07-2003 09:26 » 

Может я опять что-то не понимаю Улыбаюсь, но похоже это те же грабли, которые обсуждались в топике про BCB. Если я правильно понял заключительные выступления в том топике, то в ВСВ (читай в Дельфи) виртуальность для обработки сообщений реализована следующим образом: в классе-папе описаны переменные типа указатель на функцию обработки сообщений, а все классы-детки присваивают этим переменным указатели на собственные методы.  Ну а при обработке сообщений берется значение переменной. Такое на VC  повторить можно, но все-таки сложно. Есть гораздо более элегантные решения. Или я опять не правильно понял? Улыбаюсь
Записан
Lex
Специалист

ru
Offline Offline

WWW
« Ответ #13 : 04-07-2003 09:27 » 

Цитата

Цитата:

1. Менять вызов функции динамически


Что сие означает - вызов функции по сообщению или прямой вызов- и что мешает работать в case Не понял


По-моемому решение этогонедавно обсуждалось в теме по событиям в BCB.
Указатель на функцию и присваивай ему чего тебе надо.

Цитата

Цитата:

2. Создавать подписи на вызов в виде очереди


Это у меня вобще ассоциации вызвало только с очередями за колбасой - какие подписи???


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

Megabyte be with you!
SlavaI
Главный специалист

ru
Offline Offline

« Ответ #14 : 04-07-2003 09:28 » 

Цитата
1. Менять вызов функции динамически
меняешь указатель на класс и вызвашь разные ф-ции, если они не виртуальные.
Цитата
2. Создавать подписи на вызов в виде очереди
Тоже не понял
Цитата
Динамически подключать/отключать класс к классу
Храни указатели и подключай сколько хочешь, delete не забывай вызывать.
« Последнее редактирование: 15-04-2006 06:27 от Алексей1153 » Записан
Гром
Птычк. Тьфу, птычник... Вот!
Готовлюсь к пенсии

il
Offline Offline
Пол: Мужской
Бодрый птах


« Ответ #15 : 04-07-2003 09:33 » 

Во во - похоже Лекс и Дилетант правы - была уже темка ...
Второе - мне кажется легче все ж таки работать не с указателями, а с выбором функции через switch - case так мы не заставляем систему изгибаться.

Суть в том, что VC реагирует на любое сообщение стандартной функцией - которая зачастую обязательна для вызова, иначе нихрена не работает.

При этом можно осуществлять перехват на свою функцию, а потом в ней вызывать прямо из класса CDialog::OnChar() к примеру...

Если надо сделать разные обработчики - берется условие и дели - какие из простых ф-ий ты будешь когда вызывать и решай дергать ли собственный вынь обработчик или нет...

Насчет очереди - все надо делать ручками ...
Записан

А птичку нашу прошу не обижать!!!
SlavaI
Главный специалист

ru
Offline Offline

« Ответ #16 : 04-07-2003 09:38 » 

Сравни коды этих двух программ, и реши что тебе нужно

Код:
#include <iostream.h>

class Base
{
public:
Base(){;};
virtual ~Base(){;};
virtual void A(){ cout<<"Class Base\n"<<endl;};
};

class Derived: public Base
{
int x;
public:
virtual ~Derived(){;};
Derived():Base(),x(10){;};
virtual void A(){ cout<<"Class Derived\n"<<endl;};
};

int _tmain(int argc, _TCHAR* argv[])
{
Derived d;
Derived* ptrd = &d;
Base* ptrb = &d;
ptrb->A();
ptrd->A();
return 0;
}

Код:
#include <iostream.h>

class Base
{
public:
Base(){;};
virtual ~Base(){;};
void A(){ cout<<"Class Base\n"<<endl;};
};

class Derived: public Base
{
int x;
public:
virtual ~Derived(){;};
Derived():Base(),x(10){;};
void A(){ cout<<"Class Derived\n"<<endl;};
};

int _tmain(int argc, _TCHAR* argv[])
{
Derived d;
Derived* ptrd = &d;
Base* ptrb = &d;
ptrb->A();
ptrd->A();
return 0;
}
« Последнее редактирование: 18-11-2007 06:26 от Алексей1153++ » Записан
PSD
Главный специалист

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

« Ответ #17 : 04-07-2003 10:50 » 

То что ты описал (1,2,3) это очень похоже на СОМ  это их идеи, позднее связываение, динамическая замена компонента.

За то что это именно так говорит еще и то что идея наследована из билдера и делфи они орентированы на эту технологию и включают в себя библиотеки построеные на ней.
Записан

Да да нет нет все остальное от лукавого.
SlavaI
Главный специалист

ru
Offline Offline

« Ответ #18 : 04-07-2003 13:55 » new

А вот так можно попробовать указатель получить. Проблема получения указателя в том, что у него дурацкий тип вызова. У Майкросфт это _thiscall. Поэтому надо извращаться. Например так-

#include "stdafx.h"
#include <iostream.h>

class FuncPointer
{
};

typedef  (FuncPointer::*FPOINT)();

class Base
{
public:
   Base(){;};
   virtual ~Base(){;};
   virtual void A(){ cout<<"Class Base\n"<<endl;};
};

class Derived: public Base
{
   int x;
public:
   virtual ~Derived(){;};
   Derived():Base(),x(10){;};
   virtual void A(){ cout<<"Class Derived\n"<<endl; };
   FPOINT GetAddressOfA(){ return FPOINT(A);};
};

int _tmain(int argc, _TCHAR* argv[])
{
   Derived d;
   Derived* ptrd = &d;
   Base* ptrb = &d;
   ptrb->A();
   ptrd->A();
   FPOINT pf = ptrd->GetAddressOfA();// что с этим дальше делать?
   return 0;
}
Записан
chaka
Гость
« Ответ #19 : 05-07-2003 13:01 » 

А может все проще, может нужно просто сделать так:
Код:
#include <iostream> //for cout
#include <iomanip>  //for endl
#include <stdlib.h>   //for EXIT_SUCCESS

class Base{
    typedef int (Base::*Func)(); //pointer to member function
protected:
    Func func;
public:
    Base(){
        this->func = &Base::some_func;
    }
    virtual ~Base(){
    }
    int run(){
        return (this->*func)();
    }
    virtual int some_func(){
        std::cout << "Base::some_func" << std::endl;
        return EXIT_SUCCESS;
    }
};

class Derived : public Base{
public:
    Derived(){
    }
    virtual ~Derived(){
    }
    virtual int some_func(){
        std::cout << "Derived::some_func" << std::endl;
        return EXIT_SUCCESS;
    }
};

int main(int argc, char *argv[]){
    Base base_obj;
    base_obj.run();             //Base::some_func
    Derived derived_obj;
    derived_obj.run();        //Derived::some_func
    return EXIT_SUCCESS;
}

« Последнее редактирование: 18-11-2007 06:29 от Алексей1153++ » Записан
SlavaI
Главный специалист

ru
Offline Offline

« Ответ #20 : 06-07-2003 20:25 » 

to chaka- конечно можно и так. Просто я поначалу тормозил из-за типа указателя на ф-цию, мне надо было как-то переносимый между компиляторами вариант функтора сделать, поэтому я и сделал пустой класс- его задача обеспечить правильный тип функтора, для успокоения компилятора, а то он никак не хотел компилить.
Записан
sss
Специалист

ru
Offline Offline

« Ответ #21 : 07-07-2003 03:16 » 

SlavaI !!! Класс, в смысле круто !!!

class FuncPointer
{
};
typedef  (FuncPointer::*FPOINT)();


Я продолжу твой код:
...
FPOINT pf = ptrd->GetAddressOfA();
 __asm   
{
     mov   eax, ptrd
     call   pf
}

Зачем мне это надо ?!! Объяснить точнее, что я хочу наверное мне не дано  Так больше нельзя... . Скорее всего реакция на нельзя.
СПАСИБО !
Записан

while (8==8)
sss
Специалист

ru
Offline Offline

« Ответ #22 : 07-07-2003 04:02 » 

Цитата: Lex

Цитата:

1. Менять вызов функции динамически


Что сие означает - вызов функции по сообщению или прямой вызов- и что мешает работать в case Не понял


ответ: case не динамичен

Цитата: Lex

По-моемому решение этогонедавно обсуждалось в теме по событиям в BCB.
Указатель на функцию и присваивай ему чего тебе надо.


ответ: в том то и дело, что надо было получить этот самый указатель

Цитата

Цитата:

2. Создавать подписи на вызов в виде очереди


Это у меня вобще ассоциации вызвало только с очередями за колбасой - какие подписи???



ответ: давным давно, когда ..., и сегмент ограничивался 64k, и не было динамических массивов и классов контейнеров было такое понятие - очередь.
Записан

while (8==8)
sss
Специалист

ru
Offline Offline

« Ответ #23 : 07-07-2003 04:05 » 

Цитата: PSD
То что ты описал (1,2,3) это очень похоже на СОМ  это их идеи, позднее связываение, динамическая замена компонента.

За то что это именно так говорит еще и то что идея наследована из билдера и делфи они орентированы на эту технологию и включают в себя библиотеки построеные на ней.


Да, именно так. Только плюс RTTI, что-бы поддерживать Invoke.
Я тут покопался, RTTI входит как часть стандарта C++.
Записан

while (8==8)
SlavaI
Главный специалист

ru
Offline Offline

« Ответ #24 : 14-07-2003 05:34 » 

Посмотрел я тут на STL и заметил - к обсуждаемой здесь теме очень близка ф-ция(или класс функтора) mem_fun.
 Посмотрите ее реализацию в STL- у разных вариантов она разная, находится в заголовочном файле <functional>.
Записан
SlavaI
Главный специалист

ru
Offline Offline

« Ответ #25 : 14-07-2003 06:09 » 

В дополнение- зачем нужна эта mem_fun.
В STL в алгоритмах( например посмотри for_each- он самый простой алгоритм) все ф-ции вызываются как f(x), то есть если алгоритму передать указатель на ф-цию как &Class::Function, такая штука не пройдет, так как превратится в коде в такую вещь
Class::Function(p);
Ясное дело, что для нестатических членов класса такой вызов незаконен, а необходим такой
p->Function();
Вот ф-ция( или класс функтора) mem_fun и делает вызов нормальным по всем правилам.
Записан
SlavaI
Главный специалист

ru
Offline Offline

« Ответ #26 : 14-07-2003 10:32 » 

А на сайте появилась книга Cтрауструпа- "Язык пррограммирования C++", это наиболее авторитетная книга по C++ от самого надежного автора(он создатель языка), чтется наравне со Стандартом( также лежит на сайте).
 Книга на сайте на английском, в магазинах ее можно найти на русском.
 Попробуй там почитать о шаблонах.
Записан
Serega
Гость
« Ответ #27 : 25-07-2003 07:34 » 

Если речь идет именно о mem_fun то лучше почитать Effective STL от Мейерса, там очень хорошо описана работа этого адаптера
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines