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

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


Иначе говоря, обнаружив один роз объявление

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 существует вне зависимости от того, есть он в стандарте С++ или нет;



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

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