LINUX.ORG.RU

C++ - указатель на функции класса

 , ,


0

4

Учусь программировать) Поэтому есть такой вопрос: как вызвать функцию класса по указателю? По учебникам сделал такой пример:

#include <iostream>
using namespace std;

class s
{
public:
void (s::*IO_p) ()=&s::IO;
private:
void IO(void)  {cout<<"hello"<<endl;   };
};

int main(void)
{
s primer;
(primer.*IO_p)();
return 0;
};

Однако на строку с (primer.*IO_p)(); компилятор выдает ошибку:

Без имени.cpp:16:10: error: ‘IO_p’ was not declared in this scope

void (s::*IO_p) ()=&s::IO;

Это должно находиться в main().

Да, в реальной жизни указатели на функции класса редко нужны. С появлением С++11 — крайне редко.

JackYF ★★★★ ()

Исходный вариант не работает, потому что инициализировать поля объекта в объявлении класса можно только в C++11, а также потому что в вызове не указан объект, из которого брать указатель.

Вот рабочие примеры:

Наиболее близкий к исходному, но будет работать только для С++11.

#include <iostream>
using namespace std;

// -std=c++11

class s
{
public:
    void (s::*IO_p) ()=&s::IO;
private:
    void IO(void)  {cout<<"hello"<<endl;   };
};

int main(void)
{
    s primer;
    (primer.*primer.IO_p)();
    return 0;
}

Использование статического поля.

#include <iostream>
using namespace std;

// static member

class s
{
public:
    static void (s::*IO_p) ();
private:
    void IO(void)  {cout<<"hello"<<endl;   };
};

void (s::*s::IO_p) ()=&s::IO;

int main(void)
{
    s primer;
    (primer.*s::IO_p)();
    return 0;
}

Объявление указателя вне объекта.

#include <iostream>
using namespace std;

// standalone pointer to member function

class s
{
public:
    void IO(void)  {cout<<"hello"<<endl;   };
};

int main(void)
{
    s primer;
    void (s::*IO_p) ()=&s::IO;
    (primer.*IO_p)();
    return 0;
}

xaizek ★★★★★ ()
Ответ на: комментарий от xaizek

У меня в Makefile и так С++11 указан, так что (primer.*primer.IO_p)(); - самое то.
Ещё такой вопрос: если я создам объект через new

s *primer= new s;
то мне выдаст ошибку

Без имени.cpp:16:17: error: request for member ‘IO_p’ in ‘primer’, which is of pointer type ‘s*’ (maybe you meant to use ‘->’ ?)

Как поступить в этом случае?

Programmist11180 ★★★ ()

Если хочется сделать аналог делегата из шарпа, могу предложить готовое решение (делал когда-то в детстве):

https://bitbucket.org/kanae/cussmd/src/c794996d3863e0293544acb5104a387c81b181...

https://bitbucket.org/kanae/cussmd/src/c794996d3863/includes/misaki/delegate....

Disclaimer: этот код работает, но он был сделан во времена, когда в C++ не было шаблонов с переменным числом аргументов, и я знал этот язык даже ещё хуже, чем сейчас.

// dmfd

anonymous ()
Ответ на: комментарий от KblCb

В Qt5 указатели на функции класса нужны и важны для сигнало-слотов.

Хм, спасибо за информацию. Имел в виду, что с недавнего времени они всего лишь очень частный случай лямбд.

JackYF ★★★★ ()
Ответ на: комментарий от JackYF

с недавнего времени они всего лишь очень частный случай лямбд

Не совсем. Лямбды без замыкания это указатель на функцию, а не на функцию-член. Функция-член имеет доступ к this и вызывается из конкретного объекта. Ну и если не знать и не уметь указатели на функции, становится трудно писать функции которые принимают аргументом лямбды.

KblCb ★★★★★ ()
Ответ на: комментарий от KblCb

Лямбды без замыкания

Ну, сила лямбд именно в замыканиях, не вижу смысла рассматривать их отдельно. На практике я обычно передаю callback'и функциям, которые совсем не обязаны знать, метод какого класса будет выполнять обработку. Если я вдруг делаю С++-библиотеку — лямбда (помимо С-функции) — единственный вариант.

Но я целиком согласен, что знать неплохо, да.

JackYF ★★★★ ()
Последнее исправление: JackYF (всего исправлений: 1)
Ответ на: комментарий от KblCb

Через std::function, к примеру:

std::function< bool (const std::string&) >
JackYF ★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.