|
Программирование >> Полиморфизм без виртуальных функций в с++
Разумеется, * * должна быть лексемой языка. Но в таком случае при использовании в объявлении ее следует интерпретировать как двойную косвенность: char** р; означает char * * р Основная проблема здесь в том, что приоритет * * должен быть выше, чем у *, если мы хотим, чтобы выражение а/Ь* *с интерпретировалось, как принято в математике, т.е. а/ (Ь**с}. С одной стороны, а/Ь**р в С означает (а/Ь) * (*р), а при новых правилах семантика изменилась бы на а / (Ь* (*р) ). Очевидно, что такой код в С и С++ встречается редко. Можно было бы пойти на то, чтобы он перестал работать, если бы мы все же репшли ввести оператор возведения в степень, особенно принимая во внимание, что компилятору совсем несложно выдать предупреждение в случае возможного изменения смысла. Меня позабавило, какую реакцию вызвало мое полусерьезное предложение об использовании **. И до сих пор меня не перестает удивлять тот нешуточный пыл, с которым обсуждаются отмечено, что в большинстве случаев в Fortran-программах возведение в степень имеет вид а* *п, где п - небольшое целое число; вместо этого вполне можно написать а*а или а*а*а. И все же изложу некоторые технические соображения. Какой оператор лучше всего подошел бы в С++ на роль оператора возведения в степень? В С использованы все печатные символы из }ia6opa ASCII за исключением © и $, которые по разным причинам были сочтены непригодными. Рассматривались операторы !, -, *~, и даже одиночная (если хотя бы один операнд имеет не-интегральный тип). Однако @, $, ~ и ! присутствуют не на всех национальных клавиатурах (см. раздел 6.5.3.1); кроме того многие считали, что @ и $ плохо смотрятся в этой роли. Лексе-.мы и воспринимаются С-програ.ммистами как исключаюшее или . Вдобавок следовало обеспечить возможность комбинировать оператор возведения в степень с оператором присваивания так же, как для других арифметических операторов: например, + и = дает +=. Это сразу исключает !, поскольку ! = уже имеет семантику. Мэтт Остерн предложил * и, наверное, данное решение - лучшее из возможных. Все остальные технические вопросы можно было уладить, ориентируясь на Fortran, который является стандарто.м в этой области. Я снова вернулся к * * для обозначения оператора возведения в степень в С++. Да, я продемонстрировал, что с помощью традиционных методов невозможно использовать * * для указанной операции, но, обдумывая этот вопрос еще раз, понял, что проблему совмести.мости с С можно обойти, при.менив определенный прием при проектировании компилятора. Предположим, мы ввели оператор **. Несов.мести.мость можно устранить, если определить его семантику как разыменовать и у.множить в случае, когда второй операнд является указателем: void f(double а, double b, int* p) { a**b; означает pow(a,b) a**p; означает a*(*p) **a; ошибка: a - не указатель *p; ошибка: означает *(*p), но *p - не указатель несущественные синтаксические вопросы, например следует ли записывать возведение в степень в виде pow (а,Ь) или а**Ь, или а*Ь. 11.6.2. Операторы, определяемые пользователем Удалось бы избежать споров об операторе возведения в степень, предоставив механизм, который позволил бы пользователям определять собственные операторы? Тогда проблема отсутствия нужного оператора в общем виде была бы репгена. Когда речь заходит об операторах, неизменно обнаруживается, что того набора, который предлагают С и С++, недостаточно для выражения всех необходимых операций. Обычное рещение - определить функцию. Однако когда для класса есть воз.можность написать то запись вроде pow(a,b) abs(а) выглядит неудачно. Поэто.му есть просьбы придать смысл таки.м выражениям, как а pow b abs а Это можно сделать. Как именно - показано в Algol68. Но дальще пользователи хотят, чтобы осмысленными были и такие строки: а ** b а b la Можно сделать и это. Вопрос только в том, действительно ли стоит разрешать пользователям определять операторы самим. В [ARM] от.мечалось: Такое расширение, однако, резко усложнило бы синтаксический анализ и могло непредсказуемым образом сказаться на читаемости программы. Пришлось бы или разрешить пользователям задавать приоритет и ассоциативность новых операторов, или считать, что для всех новых операторов эти отрибуты фиксированы. В любом случае порядок вычисления вырожения вида а = b**c**d; (b**c)**d или b**(c**d)? был бы неочевиден. Понадобилось бы также разрешать синтаксические конфликты с обычными операторами. В предположении, что * * и / / определены как бинарные операторы, россмот-рим токой пример: а = а**р; а**р ИЛИ а*(*р) а = а р; *Р = 7; а = а*р = 7; может быть Следовательно, определенные пользователем операторы должны либо состоять только из обычных символов, либо включать в себя какой-то легко отличимый префикс, например . (точка): а pow b; альтернатива 1 а .pow b; альтернатива 2 а .** b; альтернатива 3 Определенным пользователем операторам следует назначить приоритет. Самый простой способ - считать, что у всех подобных операторов приоритет одинаков и совпадает с приоритетом какого-либо встроенного оператора. Однако этого недостаточно для корректного определения оператора возведения в степень. Например: operator pow: binary, precedence between * and unary Также я опасаюсь, что програм.мы, содержащие определенные пользователем операторы, для которых он же задал приоритеты, будет невозможно читать. Например, в языках программирования приоритет операции возведения в степень определяется по-разному. Поэтому пользователи станут неодинаково определять приоритет оператора pow. Значит, синтаксический анализатор будет по-разному разбирать выражение а = - b pow с * d; в разных программах. Проще присвоить всем определенным пользователем операторам один и тот же приоритет. Это решение казалось заманчивым, пока не выяснилось, что даже со своими ближайшими сотрудниками - Эндрю Кенигом и Джонатаном Шопиро - мы не можем прийти к общему мнению относительно того, каким должен быть этот приоритет. Очевидные варианты - очень высокий (скажем, выше, чем у умножения) и очень низкий (например, ниже, чем у присваивания). Увы, число случаев, когда один выбор представляется идеальным, другой - абсурд}1ым, не поддается исчислению. Так, даже простейшие примеры не удается написать правильно , если есть только один уровень приоритета. Убедитесь сами: а = b * с pow d; а = b product с pow d; a put b + c; Поэтому в С++ и нет определяемых пользователем операторов. 11.6.3. Составные операторы С++ поддерживает перегрузку унарных и бинарных операторов. Видимо, стоило бы поддержать и перегрузку составных операторов. В ARM данная идея объяснялась следующим образом: Например, два умножения в примере Matrix а, Ь, с, d; . .. а = b * с * d; можно было бы реализовать специальным оператором двойного умножения , определенным таю Matrix operator * * (Matrix&, Matrix&, Matrix&); и тогда предложение интерпретировалось бы: а = operator * * (b,c,d);
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |