Я предлагаю рассказать вашим ученикам, что что-то есть для , а не то, что есть . Позже они спросят себя: «Каков правильный инструмент для решения этой проблемы?» вместо «как называется моя проблема?»
Представьте, что вы пишете программу, которая берет растровое изображение и превращает его в файл изображения. Существуют различные виды форматов для растровых изображений (черный и белый, настоящий цвет, настоящий цвет с альфа-каналом и т. Д.). И есть различные форматы файлов изображений (JPEG, PNG, GIF). Если вы попытаетесь написать это без указателей на функции, вы получите N * M алгоритмов: N для числа входных растровых изображений и M для числа поддерживаемых форматов вывода. В этом базовом примере это будет 9 (3 * 3). Завтра твой босс придет и тоже хочет поддержать TIFF. Это будет означать 12 (3 * 4) алгоритмов. Небольшое изменение в спецификациях вызывает много работы. Тупик.
Но вы можете определить три функциональных указателя: getWidth(bitmap)
, getHeight(bitmap)
, getPixel(bitmap, x, y)
Теперь вам нужно только N алгоритмов, которые реализуют эти три FP. Каждый алгоритм работает с каждым видом растрового изображения и знает, как его прочитать. Алгоритм вывода больше не заботится о том, как выглядит входное изображение, они просто берут три FP, чтобы получить доступ к данным абстрактного изображения. Таким образом, вы получаете 6 (3 + 3) алгоритмов, и когда ваш босс приходит с TIFF, вам нужно добавить только один алгоритм: 7 вместо 12.
С точки зрения компьютера, FP - это батут. Вместо того, чтобы начинать выполнять код по адресу FP (обычный вызов функции), он считывает сохраненный там адрес и начинает выполнять код, по которому адрес, сохраненный в FP, указывает на
Забавный код, который вам нужно написать, предназначен только для того, чтобы компилятор был доволен. В ассемблере это выглядит довольно просто. Обычный вызов функции:
lea.l someFunction,a0 # Load address of someFunction
jsr.l a0 # Jump to subroutine
Указатель функции:
lea.l functionPointer,a0 # Load address of functionPointer
move.l (a0),a0 # Load what is stored at functionPointer into a0
jsr.l a0 # Jump to subroutine
Как видите, разница только в одной инструкции.