![]() |
|
Программирование >> Дополнительные возможности наследования
Макросы Директиву #def ine можно также использовать для создания макросов. Макрос - это лексема, созданная с помощью директивы #define. Он принимает параметры подобно обычной функции. Препроцессор заменяет строку подстановки любым заданным параметром. Например, макрокоманду TWICE можно определить следующим образом: #define TWICE(x) ( (х) . 2 ) А затем в программе можно записать следующую строку: TWICE(4) Целая строка TWICE(4) будет удалена, а вместо нее будет стоять значение 8! Когда препроцессор считывает параметр 4, он выполняет следующую подстановку: ((4) * 2), это выражение затем вычисляется как 4 2 и в результате получается число 8. Макрос может иметь больше одного параметра, причем каждый параметр в тексте замены может использоваться неоднократно. Вот как можно определить два часто используемых макроса - МАХ и Ml N: #define МАХ(х,у) ( (х) > (у) (х) : (у) ) #define MIN(x,y) ( (х) < (у) ? (х) : (у) ) Обратите внимание, что в определении макроса открывающая круглая скобка для списка параметров должна немедленно следовать за именем макроса, т.е. между ними не должно быть никаких пробелов. Препроцессор, в отличие от компилятора, не прощает присутствия ненужных пробелов. Если записать #define МАХ (х,у) ( (х) > (у) ? (х) : (у) ) и попытаться использовать макрос МАХ int X = 5, у = 7, z; Z = МАХ(х,у); то промежуточный код будет иметь следующий вид: int X = 5, у = 7, z; Z = (х,у) ( (X) > (у) ? (X) : (у) )(х,у) В этом случае сделана простая текстовая замена, а не вызов макроса, т.е. лексема МАХ была заменена выражением (х,у) ( (х) > (у) ? (х) : (у) ),за которым сохранилась строка (х,у). Однако после удаления пробела между словом МАХ и списком параметров (х,у) промежуточный код выглядит уже по-другому: int X = 5, у = 7, z; Z =7; Зачем нужны все эшн круглые скоОкн Вам может показаться странным, что в макросах используется так много круглых скобок. На самом деле препроцессор совсем не требует, чтобы вокруг параметров в строке подстановки ставились круглые скобки, но эти скобки помогают избежать не- желательных побочных эффектов при передаче макросу сложных значений. Например, если определить МАХ как tfdefine МАХ(х,у) х > у ? х : у и передать значения 5 и 7, то макрос МАХ будет нормально работать. Но если передать более сложные выражения, можно получить неожиданные результаты, как показано в листинге 21.2. Листинг 21.2. ИсиоАЬЗсваиие в макрвсе крувАЫх сквОвк 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 Листинг 21.2. Использование в макросе круглых скобок #include <iostream.h> #define CUBE(a) ( (a) * (a) (a) ) tfdefine THREE(a) a * a * a int main() { long X = 5; long у = CUBE(x); long z = THREE(x); cout << y: << у << endl; cout z: << z endl; long a = 5, b = 7; у = CUBE(a+b); z = THREE(a+b); cout y: << у endl; cout z: z << endl; return 0; 125 125 1728 82 В строке 4 определяется макрос CUBE с параметром х, который заключается в круглые скобки при каждом его использовании в выражении. В строке 5 определяется макрос THREE, параметр которого используется без круглых скобок. При первом использовании этих макросов параметру передается значение 5, и оба макроса прекрасно справляются со своей работой. Макрос CUBE(5) преобразуется в выражение ( (5) (5) (5) ), которое при вычислении дает значение 125, а макрос THREE(5) прейбразуется в выражение 5 5 5, которое также возвращает значение 125. При повторном обращении к этим макросам в строках 16-18 параметру передается выражение 5 + 7. В этом случае макрос CUBE(5+7) преобразуется в следующее выражение: ( (5+7) . (5+7) . (5+7) ) Подставляемые функции Часто вместо макросов удобно объявить подставляемую функцию. Например, в листинге 21.3 создается функция CUBE, которая выполняет ту же работу, что и макрос CUBE в листинге 21.2, но в данном случае это делается способом, обеспечивающим контроль за соответствием типов. ( (12) . (12) . (12) ) При вычислении этого выражения получаем значение 1728. Однако макрос THREE(5+7) преобразуется в выражение иного вида; 5 + 7*5 + 7.5 + 7 А поскольку операция умножения и.меет более высокий приоритет по сравнению с операцией сложения, то предыдущее выражение эквивалентно следующему: 5 + (7 5) + (7 . 5) + 7 После вычисления произведений в круглых скобках получаем выражение 5 + (35) + (35) + 7 После суммирования оно возвращает зггачснис 82. Макросы в сравнении с функциями шаОлонпв При работе с макросами п языке С++ можно столкнуться с чегырьмя проблемами. Первая состоит в возможных псудоГ)СТЕ!ах при увеличении самого выражения макроса, поскольку любой макрос должен быть определен в одной строке. Безусловно, эту строку можно продлить с помощью символа обратной косой черты (\), но большие макросы сложны для понимания и с ними грудио работать. Вторая проблема cocToirr н том. что макросы вьпюлняюгся путем подстановки их выражений в код программы при каждом выюве. Эго озЕИчает, что если макрос используется 12 раз, то ctojhjKo же раз в Biiiuy программу будет вставлено соответствующее выражение (вместо одною рази, как при обращении к обычной функции). Хотя, с другой стороны, подставляемые выражении обычно работают быстрее, чем вызовы функций, поскольку не тратится время па само обращение к функции. Тот факт, что макросы выполняются путем подстановки выражений в код программы, приводит к третьей проблеме, которая проявляется в том, что макросы огсуг-ствуют в исходном коде программы, используемом компилятором для ее тестирования. Это может существенно затруднить отладку программы. Однако наиболее существенна послс;цгяя проблема: в макросах не поддерживается контроль за соответствием типов даипых. Хотя возможность ис1гользования в макросе абсолютно любого параметра кажется удобной, эгот факт полностью подрывает строгий контроль типов в С++ и является проклятием для программистов на С++. Конечно, сушествует корректный способ решить и эту проблему - нужно воспользоваться услугами шаблонов, как было показано на занятии 19.
|
© 2006 - 2025 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки. |