Как получить указатель на функцию для функции-члена класса, а затем вызвать эту функцию-член с конкретным объектом? Я хочу написать:
class Dog : Animal
{
Dog ();
void bark ();
}
…
Dog* pDog = new Dog ();
BarkFunction pBark = &Dog::bark;
(*pBark) (pDog);
…
Также, если возможно, я хотел бы вызвать конструктор и через указатель:
NewAnimalFunction pNew = &Dog::Dog;
Animal* pAnimal = (*pNew)();
Возможно ли это, и если да, то каков предпочтительный способ сделать это?
c++
function-pointers
class-method
Тони Пони
источник
источник
Dog dog;
), скорее всего, то, что вам нужно.Ответы:
Прочтите это для подробностей:
источник
*this.*pt2Member
будет работать.*
имеет больший приоритет над.*
... Лично я бы все равно написалthis->*pt2Member
, что на одного оператора меньше.pt2ConstMember
доNULL
?(object.*method_pointer)
так, поэтому мы хотим,*
чтобы у них был больший приоритет.this
просто используется для демонстрации того, что все, к чему вы.*
относитесь, должно быть указателем на экземпляр (подкласса). Однако для меня это новый синтаксис, я только предполагаю, основываясь на других ответах и ресурсах, связанных здесь. Я предлагаю отредактировать, чтобы сделать это более ясным.Проще всего начать с файла
typedef
. Для функции-члена вы добавляете имя класса в объявление типа:Затем для вызова метода вы используете
->*
оператор:Я не верю, что с такими конструкторами можно работать - ctors и dtors особенные. Обычный способ добиться такого рода вещей - использовать фабричный метод, который в основном представляет собой статическую функцию, вызывающую за вас конструктор. См. Пример кода ниже.
Я изменил ваш код, чтобы в основном делать то, что вы описываете. Ниже приведены некоторые предостережения.
Теперь, хотя вы обычно можете использовать
Dog*
вместо знакаAnimal*
благодарности магию полиморфизма, тип указателя на функцию не соответствует правилам поиска иерархии классов. Таким образом, указатель на метод Animal несовместим с указателем на метод Dog, другими словами, вы не можете присвоитьDog* (*)()
a переменной типаAnimal* (*)()
.Статический
newDog
метод - это простой пример фабрики, которая просто создает и возвращает новые экземпляры. Будучи статической функцией, она имеет обычныйtypedef
(без классификатора).Ответив на вышесказанное, мне интересно, нет ли лучшего способа добиться того, что вам нужно. Есть несколько конкретных сценариев, в которых вы бы поступили подобным образом, но вы можете обнаружить, что есть другие шаблоны, которые лучше подходят для вашей проблемы. Если вы опишете в более общих выражениях, чего пытаетесь достичь, коллективный разум может оказаться еще более полезным!
В связи с вышесказанным, вы, несомненно, найдете очень полезными библиотеку привязки Boost и другие связанные модули.
источник
->*
раньше, но теперь я надеюсь, что мне это никогда не понадобится :)Я не думаю, что кто-то объяснил здесь, что одна из проблем заключается в том, что вам нужны « указатели на элементы », а не обычные указатели на функции.
Указатели на элементы функций - это не просто указатели на функции. С точки зрения реализации, компилятор не может использовать простой адрес функции, потому что, как правило, вы не знаете адрес для вызова, пока не узнаете, для какого объекта разыменовать (подумайте о виртуальных функциях). Вам также необходимо знать объект, чтобы
this
, конечно же, предоставить неявный параметр.Сказав, что они вам нужны, теперь я скажу, что вам действительно нужно их избегать. Серьезно, указатели на члены - это боль. Гораздо разумнее взглянуть на объектно-ориентированные шаблоны проектирования, которые достигают той же цели, или использовать
boost::function
или что-то еще, как упомянуто выше, если вы сделаете этот выбор, то есть.Если вы предоставляете этот указатель на функцию существующему коду, поэтому вам действительно нужен простой указатель на функцию, вам следует написать функцию как статический член класса. Статическая функция-член не понимает
this
, поэтому вам нужно передать объект в качестве явного параметра. Когда-то была довольно необычная идиома в этих строках для работы со старым кодом C, которому нужны указатели на функции.Поскольку
myfunction
на самом деле это обычная функция (не считая проблем с областью видимости), указатель на функцию можно найти обычным способом C.РЕДАКТИРОВАТЬ - этот вид метода называется «методом класса» или «статической функцией-членом». Основное отличие от функции, не являющейся членом, состоит в том, что если вы ссылаетесь на нее извне класса, вы должны указать область с помощью
::
оператора разрешения области. Например, чтобы получить указатель на функцию, используйте&myclass::myfunction
и для его вызова используйтеmyclass::myfunction (arg);
.Подобные вещи довольно распространены при использовании старых API Win32, которые изначально были разработаны для C, а не C ++. Конечно, в этом случае параметром обычно является LPARAM или аналогичный, а не указатель, и требуется некоторое приведение типов.
источник
источник
Минимальный запускаемый пример
main.cpp
Скомпилируйте и запустите:
Протестировано в Ubuntu 18.04.
Вы не можете изменить порядок скобок или опустить их. Следующие действия не работают:
GCC 9.2 завершится ошибкой:
Стандарт C ++ 11
.*
и->*
являются одиночными операторами, введенными в C ++ для этой цели и отсутствующими в C.Стандартный проект C ++ 11 N3337 :
.*
и->*
.источник
Я пришел сюда, чтобы узнать, как создать указатель на функцию (а не указатель на метод) из метода, но ни один из ответов здесь не дает решения. Вот что я придумал:
Итак, для вашего примера вы бы теперь сделали:
Изменить:
используя С ++ 17, есть еще лучшее решение:
который можно использовать напрямую без макроса:
Для методов с такими модификаторами, как
const
вам могут потребоваться дополнительные специализации, например:источник
Причина, по которой вы не можете использовать указатели функций для вызова функций-членов, заключается в том, что обычные указатели на функции обычно являются просто адресом памяти функции.
Чтобы вызвать функцию-член, вам нужно знать две вещи:
Указатели на обычные функции не могут хранить и то, и другое. Указатели функций-членов C ++ используются для хранения a), поэтому вам необходимо явно указать экземпляр при вызове указателя функции-члена.
источник
Указатель функции на член класса - это проблема, которая действительно подходит для использования boost :: function. Небольшой пример:
источник
Чтобы создать новый объект, вы можете либо использовать новое размещение, как упомянуто выше, либо реализовать в вашем классе метод clone (), который создает копию объекта. Затем вы можете вызвать этот метод клонирования с помощью указателя на функцию-член, как описано выше, для создания новых экземпляров объекта. Преимущество клонирования заключается в том, что иногда вы можете работать с указателем на базовый класс, когда вы не знаете тип объекта. В этом случае проще использовать метод clone (). Кроме того, clone () позволит вам скопировать состояние объекта, если вы этого хотите.
источник
Я сделал это с помощью std :: function и std :: bind ..
Я написал этот класс EventManager, который хранит вектор обработчиков в unordered_map, который сопоставляет типы событий (которые являются просто const unsigned int, у меня их большое перечисление в области имен) на вектор обработчиков для этого типа события.
В моем классе EventManagerTests я настроил обработчик событий, например:
Вот функция AddEventListener:
Вот определение типа EventHandler:
Затем снова в EventManagerTests :: RaiseEvent я делаю следующее:
Вот код для EventManager :: RaiseEvent:
Это работает. Я получаю вызов в EventManagerTests :: OnKeyDown. Мне нужно удалить векторы, наступает время очистки, но как только я это сделаю, утечек не будет. Создание события на моем компьютере занимает около 5 микросекунд, это примерно в 2008 году. Не совсем быстро, но. Достаточно справедливо, если я знаю это и не использую это в сверхгорячем коде.
Я хотел бы ускорить его, свернув свои собственные std :: function и std :: bind, и, возможно, используя массив массивов, а не unordered_map векторов, но я не совсем понял, как сохранить функцию-член указатель и вызовите его из кода, который ничего не знает о вызываемом классе. Ответ Ресницы выглядит очень интересно ..
источник