|
Программирование >> Полиморфизм без виртуальных функций в с++
Иначе говоря, обнаружив один роз объявление Matrix operator * * (Matrix&, Matrix&, Matrix&); компилятор начнет искать повторяющиеся умножения Matrix и вызывать для их интерпретации функцию. Слишком сложные для интерпретации последовательности будут обрабатываться обычными (унарными и бинарными) операторами. Такое расширение предлагалось несколько раз кок эффективный способ обработки повторяющихся вычислений в научных расчетах, где используются определенные пользователем типы. Например, оператор Matrix operator = * + ( Matrix&, const Matrix&, double, const MatrixSc можно было бы использовать для обработки предложений типа: a=b*1.7+d; Естественно, пробел в таких объявлениях очень важен. Впрочем, вместо него для обозначения позиций операндов можно было использовать и любую другую лексему: Matrix operator.=.*.+.( Matrix&, const Matrix&, double, const Matrix& До выхода ARM я никогда не видел изложения этого решения в печати, но такая техника часто применяется в кодогенераторах. Данная идея представляется многообещающей для поддержки оптимизированных операций с векторами и матрицами, но у меня так и не нашлось вре.мени продумать ее до конца. В существующей нотации это было бы неплохой поддержкой старого приема, заключающегося в определении функций для выполнения составных операций над переданными аргументами. 11.7. Перечисления в с концепция перечислений выглядит незаконченной. В первоначальном варианте языка их не было. Перечисления ввели без всякой охоты в качестве уступки тем, кто настойчиво требовал более основательных символических констант, чем препроцессорные макросы без параметров. Поэтому в С значение перечислителя имеет тип int, равно как и значение переменной, объявленной как имеющая тип перечисления. Значение типа int .можно присваивать переменной типа перечисления. Например: enum Color { red, green, blue }; void f() /* функция С */ enum Color с = 2; /* правильно */ int i = С; /* правильно */ Для тех стилей программирования, которые должен был поддерживать С++, ие было нужды в перечислениях, поэтому правила С перешли в С++ без изменения. Правда, в комитете ANSI С изменили или, если хотите, уточнили определение перечислений таким образом, что указатели на разные перечисления оказались разными типами: enum Vehicle { car, horse buggy, rocket }; void g(pc,pv) enum Color* pc; enum Vehicle* pv; ( pc = pv; /* возможно, некорректно в ANSI С */ Я долго обсуждал возникшую проблему с таки.ми экспертами по С, как Дэвид Хансон (David Hanson), Брайан Керниган, Эндрю Кениг, Дуг Макилрой, Дэвид Проссер и Деннис Ричи. Мы так и не смогли прийти к окончательно.му выводу -что само по себе было недобрым знаком, - но решили, что в комитете собирались объявить этот пример незаконным. Меня такая неопределенность не устраивала из-за перегрузки функций. Так, я должен знать, что объявлено в следуюп1ем примере: void f(Color*); void f(Vehicle*); Одна и та же функция, объявленная дважды, или две перегруженные функции? Уверен, что формулировки всегда должны быть четкими, а оставлять решение на усмотрение разработчика компилятора не стоит. Аналогичный пример void f(Color); void f(Vehicle); также должен интерпретироваться однозначно. В С и С++ в том виде, в каком последний сушествовал до выхода ARM, это считалось одной функцией, объявленной дважды. Однако правильнее было бы рассматривать каждое перечисление как отдельный тип. Например: void h() С++ { Color с = 2; ошибка с = Color(2); правильно: 2 явно преобразуется в Color int i = с; правильно: с неявно преобразуется в int При обсуждении перечислений с программиста.ми на С++ кто-нибудь всегда громко требовал именно такого решения проблемы. Быть .может, я и действовал чересчур стремительно, но принятый вариант является лучши.м. 11.7.1 Перегрузка на базе перечислений я упустил из виду очевидный факт: раз каждое перечисление - это отдельный тип, определенный пользователем, следовательно, он имеет все те же права, что и класс. В таком случае, на базе перечислений .можно перегружать операторы. Указал на это Мартин ОРиордан (Martin ORiordan) на заседании комитета ANSI/ISO. Вместе с Дэгом Брюком они проду.мали все детали, и перегрузка на базе перечислений была включена в С++. Например: enum Seaso.n { winter, spring, summer, fall } ; Season operator++(Season s) { switch (s) { case winter: return spring; case spring: return summer; case summer: return fall; case fall: return winter; } Я при.менял такие переключатели, чтобы избежать приведений типов и операций над целы.ми числами. 11.7.2. Тип Boolean Одно из самых распространенных перечислений - .это enum bool { false, true }; В любой сколько-нибудь сложной программе можно встретить нечто похожее, например: #define bool char #define Bool int typedef unsigned int BOOL; typedef enum { F, T } Boolean; const true = 1; #define TRUE 1 #define False (!True) Примеры .можно множить до бесконечности. Однако семантика большинства вариантов слегка различается и при совместном использова1ШИ в программе нескольких вариантов возникает конфликт. Конечно, данная проблема была известна давно. Естественно, прежде всего на ум приходит мысль определить перечисление. Однако Дэг Брюк и Шон Корфилд изучили сотни тысяч строк на С++, и выяснилось, что в больншнстве случаев при использовании типа Boolean необходимо свободно преобразовывать его в int и обратно. Поэтому определение Boolean в виде перечисления испортило бы слишком много программ. Так стоит ли вообше о не.м беспокоиться, если: □ тип Boolean существует вне зависимости от того, есть он в стандарте С++ или нет;
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки. |