forum.boolean.name

forum.boolean.name (http://forum.boolean.name/index.php)
-   C++ (http://forum.boolean.name/forumdisplay.php?f=22)
-   -   Указатели на функции. (http://forum.boolean.name/showthread.php?t=15043)

impersonalis 03.07.2011 02:09

Указатели на функции.
 
В общем случае - приходилось работать с данным "явлением". Однако сейчас, я столкнулся с "указателем на функцию-член класса".
Погуглил и вот что выудил (спешу поделиться с общественностью):
В моей программе (поток нафиг не по теме, но что-то придумать иного семпла, кроме как актуального кода не могу):
класс MyCl* сожержит структуру MyStr (структура с параметрами потока, которым класс управляет); в структуре содержатся данные о том, какую функцию из родительского экземпляра класса MyCl поток (дескриптор которого является компонентом структуры MyStr, входящей в состав класса MyCl, и получающий экземпляр структуры MyStr как бестиповой указатель в момент создания) должен запускать (при определённом стечении обстоятельств). Т.к. хотелось иметь универсальный инструмент и конфигурировать его в момент задания MyStr, пришлось отказаться от явного обращения к функции по имени.
Структура:
Код:

class MyCl;
struct MyStr{
HANDLE Thread;
THREAD_CONTROL Control;
MyCl *ParentInterface;
void (MyCl::*FunctionPtr)(WORD,void*,void*);
};

Класс (func1,func2,func3 - большое разнообразие возможных функций):
Код:

class MyCl{
private:
MyStr ControlThread;
void func1(WORD,void*,void*);
void func2(WORD,void*,void*);
void func3(WORD,void*,void*);
public:
MyCl();
~MyCl();
}

Функция, которую выполняет поток
Код:

DWORD WINAPI ThreadFunction(PVOID);
DWORD WINAPI ThreadFunction(PVOID Param){
        MyStr *PC=(MyStr*)Param;
        while (true){
                (PC->ParentInterface->*(PC->FunctionPtr))(0,0,0);
                Sleep(5000);
                if(PC->Control==TH_STOP)break;
        }
        return 0;
}

Синим выделена, выносящая мозг конструкция, являющаяся вызовом функции, по указателю FunctionPtr, из экземпляра ParentInterface.
Как получить адрес функции:
Код:

ControlThread.FunctionPtr=&MyCl::func1;
В ParentInterface запихивается указатель на родительский экземпляр MyCl.
Меняя эту строку, можно программировать поведение потока, не нагромождая конструкции из всех возможных case

*-имена вымышлены, куски кода выкинуты для упрощения пониамния; в действительности код грамотно разбит на объявление и реализацию.

impersonalis 15.05.2014 17:53

Ответ: Указатели на функции.
 
Жутко накрученный пример в 1-ом посте. Вот попроще набросал:
Код:

#include <iostream>

using namespace std;

class Object{
    private:
        static unsigned short counter;
        unsigned short ID;
    public:
        Object();
        void Show(char s)const;
};

unsigned short Object::counter=0;

Object::Object(){
    this->counter++;
    this->ID=counter;
}

void Object::Show(char s)const{
    cout<<'['<<this->ID<<"]: "<<s<<endl;
}

int main()
{
    void (Object::*FuncPtr)(char s)const = &Object::Show;

    Object x1;
    Object x2;

    (x1.*FuncPtr)('a');
    (x2.*FuncPtr)('b');

    x1.Show('a');
    x2.Show('b');

    return 0;
}

Пример (среди прочего) доступно демонстрирует момент архитектуры. Функции для всех объектов класса создаются в единственном экземпляре единожды. Уточнение, для какого объекта функция вызывается (если функция не статическая) необходимо только непосредственно в момент вызова (чтобы определить к какой копии набора компонентов класса обращаться).
Сравни то же на Б3Д
Код:

Type TObject
        Field ID%
End Type

Global TObject__counter%=0

Function TObject__TObject.TObject()
        Local TObj.TObject=New TObject
        TObject__counter=TObject__counter+1
        TObj\ID=TObject__counter
        Return TObj
End Function

Function TObject__Show(TObj.TObject,s$)
        Print "["+Str(TObj\ID)+"]: "+s
End Function

x1.TObject=TObject__TObject()
x2.TObject=TObject__TObject()

TObject__Show(x1,"a")
TObject__Show(x2,"b")

WaitKey()
End

Синтаксис C++ позволяет реализовать вызов TObject__Show(x1,"a") как x1.TObject__Show("a"). При этом функция TObject__Show по-прежнему размещается в памяти единожды.

HolyDel 15.05.2014 18:17

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

impersonalis 15.05.2014 18:22

Ответ: Указатели на функции.
 
Цитата:

Сообщение от HolyDel (Сообщение 280807)
в новом движке использую такой подход для вызова метода куллинга.
хотя есть мнение что кейс все равно будет быстрее.
надо потестить

имхо, в зависимости от деталей реализации case может убавить портабельности коду, раздувшись во всех местах "разыменования". С другой стороны, он выглядит более безопасным для программиста, и очевидным для статического анализатора.
Вот ещё занятная вещица:
Код:

#include <iostream>

using namespace std;

class Object{
    private:
        static unsigned short counter;
        unsigned short ID;
    public:
        Object();
        void Show(char s)const;
        void Show2(char s)const;
        void Show3(char t[])const;
};

unsigned short Object::counter=0;

Object::Object(){
    this->counter++;
    this->ID=counter;
}

void Object::Show(char s)const{
    cout<<'['<<this->ID<<"]: "<<s<<endl;
}

void Object::Show2(char s)const{
    cout<<'{'<<this->ID<<"}: "<<s<<endl;
}

void Object::Show3(char t[])const{
    cout<<'<'<<this->ID<<">: "<<t<<endl;
}

int main()
{
    void (Object::*FuncPtr)(char s)const = &Object::Show;
    void (Object::*FuncPtr2)(char s)const = &Object::Show2;
    void (Object::*FuncPtr3)(char t[])const = &Object::Show3;

    Object x1;

    (x1.*FuncPtr)('a');
    (x1.*FuncPtr2)('z');
    (x1.*FuncPtr3)("xx");

    cout<<"addr "<<FuncPtr<<endl;
    cout<<"addr "<<FuncPtr2<<endl;
    cout<<"addr "<<FuncPtr3<<endl;

    cout<<"addr "<<(void*)FuncPtr<<endl;
    cout<<"addr "<<(void*)FuncPtr2<<endl;
    cout<<"addr "<<(void*)FuncPtr3<<endl;

    return 0;
}


Без (да-да, я знаю, так делать не надо) приведения к типу void* указатель отображает единицу для всех трёх функций (или только у меня? :4to: ).

HolyDel 15.05.2014 18:53

Ответ: Указатели на функции.
 
Цитата:

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


Часовой пояс GMT +4, время: 08:40.

vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot