Программирование >>  Полиморфизм без виртуальных функций в с++ 

1 ... 78 79 80 [ 81 ] 82 83 84 ... 144


Разумеется, * * должна быть лексемой языка. Но в таком случае при использовании в объявлении ее следует интерпретировать как двойную косвенность:

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);



1 ... 78 79 80 [ 81 ] 82 83 84 ... 144

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика