Страница 1 из 2
Запуск функции,на которую указатель указывает
Добавлено: 17 июн 2005, 15:24
Lev
/*
В зависимости от ситуации указатель может указывать на одну функцию или другую (Fun1 или Fun2).
И, когда придет время, необходимо выполнять функцию, на которую указывает указатель
*/
Код: Выделить всё
class bclass{
public:
// указатель(не обязательно как тут типа) для указания на функцию Fun1 или Fun2
void *AddressOfFun;
virtual int Fun1(int u)
{return (u*2+1);}
virtual int Fun2(int u)
{return (u*2+2);}
virtual void Choice(int selector)
{
if(selector==0)
{
// указатель будет указывать на Fun1
///AddressOfFun = Fun1;
}
else
{
// указатель будет указывать на Fun2
///AddressOfFun = Fun2;
}
}
};
void main()
{
bclass ob;
ob.Choice(1);
// нужно выполнить функцию, на которую
// указывает указатель AddressOfFun
///ВЫПОЛНИТЬ(ФУНКЦИЮ,на которую указывает ob.AddressOfFun; С ПАРАМЕТРОМ u=2);
}
/*можно, конечно, каждой функции присвоить свой уникальный номер, но когда их станет много?
появятся накладные расходы, т.к. нужно будет switch ставить*/
Добавлено: 17 июн 2005, 16:33
Absurd
Ты вообще затронул концептуальную проблему C++ - указатели на функции - члены. Достойного решения этой проблемы, честно говоря, нет.
Указатель на функцию - член класса может указывать только на метод своего класса. Он не может указывать на метод производного класса
Это происходит потому что в С++ есть множественное и виртуальное наследование. Указатель на метод класса с двумя или несколькими предками (некоторые из которых возможно виртуальные предки) занимает больше чем 4 байта. Он содержит не только адрес первого байта функции, но и некоторую служебную информацию. Поэтому указатель на функцию - член нельзя привести к четырехбайтовому void*
Вариант рашения 1 - Интерфейсы + множественное наследование.
Java - образный подход. Не пользуемся указателями на методы вообше, используем интерфейсы и множественное наследование.
Если надо реализовать callback-вызовы, включаем интерфейс с этими вызовами в список наследования, реализуем его методы, а потом передаем всем объектам, которые хотят нас о чем то информировать указатель this.
Вариант рашения 2 - Интерфейсы + вложенные классы.
Тоже Java - образный подход. В Java это все делается намного прямее, поскольку вложенные классы в Java имеют внутреннюю ссылку на охватывающий объект, в контексте которого они были порождены.
Если надо реализовать callback-вызовы, делаем вложенный класс унаследованный от интерфейса, реализуем в нем методы, а потом передаем всем объектам, которые хотят нас о чем то информировать указатель этот объект-переходник. Этот переходник должен содержать ссылку на охватывающий класс. Кроме того, он должен быть объявлен как friend чтобы иметь доступ к private&protected полям охватывающего класса.
Вариант рашения 3 - хаки
Delphi-образный подход. Мы имеем объекты - события, кторым можно присвоить любой метод любого объекта, и дергаем за них. Поскольку в С++ event'ов нет, нужны хаки. Есть два распространенных хака - boost::function и Loki::Functor.
Принцип у них один - впердоливание указателей на методы в пристойный интерфейс при помощи шаблонов. Поскольку указатели на методы в С++ могут быть размером байтов в двадцать, эти хаки не рискуют инкапсулировать в себе указатель, а размещают его в динамической памяти.
boost::function Имеет в себе много хака. но он работает даже на VC++6.0
Loki::Functor Почти не имеет в себе хака. Внутренний объект-пререходник размещает в специальном спуле для мелких объектов (Зачот). Но требует компилятора, совместимого со cтандартом ansi-iso-iec с++. Микрософтовские компиляторы (кроме самого последнего от 2004 года) отпадают. Так что эта радость доступна только пользователям Intel C++, Metrowerk CodeWarrior C++ или g++.
Добавлено: 17 июн 2005, 17:53
Lev
ok, спасибо.
Для окончательного грузона я пойду читать книгу Андрея Александреску
Добавлено: 18 июн 2005, 11:11
Absurd
Это шутка? Чтобы понимать А. Александреску, надо быть гуру в С++ и при этом разбираться в языках подобных Lisp.
Добавлено: 18 июн 2005, 17:02
Lev
всё, разобрался. Значит я уже не новичёк в програмировании.
Код: Выделить всё
using namespace std;
class bclass;
// определение типа для указания на член класса -на функцию
// функция возвращает int и принимает в качестве параметра int
typedef int (bclass::* TpMemFun)(int);
class bclass{
public:
// создание указателя на функцию
TpMemFun pToFun;
virtual int Fun1(int u)
{
cout << "Fun1 ... \n";
return (u*2+1);
}
virtual int Fun2(int u)
{
cout << "Fun2 ... \n";
return (u*2+2);
}
virtual void Choice(int selector)
{
if(selector==0)
{
pToFun = Fun1;
}
else
{
pToFun = Fun2;
}
}
};
void main()
{
bclass ob;
ob.Choice(1);
(ob.*(ob.pToFun))(7);
ob.Choice(0);
(ob.*(ob.pToFun))(7);
}
Добавлено: 18 июн 2005, 17:04
Lev
Неудобно, то что форум не отображает раскраску текста как в компиляторе.
Добавлено: 18 июн 2005, 18:45
Absurd
А зачем ты объявил Fun1 и Fun2 как virtual?
Если ты перегрузишь их в производном классе, все равно будут работать функции из базового. В С++ нет типа "указатель на виртуальный метод"
Добавлено: 19 июн 2005, 07:38
Lev
Результат выполнения программы:
bclass::Fun2 ...
derived::Fun2 ...
Press any key to continue
Код: Выделить всё
using namespace std;
class bclass;
typedef int (bclass::* TpMemFun)(int);
class bclass{
public:
TpMemFun pToFun;
virtual int Fun1(int u)
{
cout << "bclass::Fun1 ... \n";
return (u*2+1);
}
virtual int Fun2(int u)
{
cout << "bclass::Fun2 ... \n";
return (u*2+2);
}
virtual void Choice(int selector)
{
if(selector==0)
{
pToFun = Fun1;
}
else
{
pToFun = Fun2;
}
}
};
class derived: public bclass{
virtual int Fun2(int u)
{
cout << "derived::Fun2 ... \n";
return (u*2+2);
}
};
void main()
{
/*bclass ob;
ob.Choice(1);
(ob.*(ob.pToFun))(7);
ob.Choice(0);
(ob.*(ob.pToFun))(7);*/
bclass obBase;
derived obDerived;
bclass *pBase;
pBase = &obBase;
pBase->Choice(1);
(pBase->*(pBase->pToFun))(7);
pBase = &obDerived;
pBase->Choice(1);
(pBase->*(pBase->pToFun))(7);
}
Добавлено: 20 июн 2005, 10:57
Eugie
В С++ нет типа "указатель на виртуальный метод"
Обычный указатель на метод работает без проблем в случае виртуальных методов.
В сторону (шепотом): так ли уж нужны указатели на методы?

ИМХО, в отличие от указателей на функции, без них вполне можно жить.
Добавлено: 21 июн 2005, 02:22
Absurd
В сторону (шепотом): так ли уж нужны указатели на методы?
Согласен, жить можно. В Java даже живут (Если закрыть глаза на java.lang.reflect.Method).
НО лично мне кажется хлопотным применять каждый раз наследование и интерфейсы для получения callback - сущности.
Указатели на методы С++ совершенно неудобоваримы. Их толком никто не использует. Их можно использовать только вместе с шаблонами в телегах типа std::mem_fun или std::mem_fun_ref. Или тот же boost::function.
Между тем, авторам компиляторов было бы проще сделать нормальные closures, которым можно привязать любой метод любого объекта с подходящей сигнатурой. И код вызова через такой closure был бы таким:
mov ecx, this
call method