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

1 ... 27 28 29 [ 30 ] 31 32 33 ... 144


При каждом вызове конструктора X: : X (int) память будет выделяться с помощью my alloc (). Этот механизм вполне справляется со своей непосредственной задачей и с некоторыми другими тоже, но он слишком низкоуровневый, плохо сочетается с управлением стеком и наследованием, подвержен ошибкам и должен применяться слишком часто, поскольку типичный класс имеет много конструкторов.

Статические и автоматические (с выделением памяти из стека) объекты всегда было возможно создать, и именно для них управление памятью реализуется максимально эффективно. Типичный пример - класс String. Его объекты обычно создаются в стеке, следовательно, не требуют явного управления памятью, а необходимая для них свободная память распределяется невидимо для пользователя функциями-членами класса.

Примененная выше нотация для записи конструкторов обсуждается в разделах 3.11.2 и 3.11.3.

3.10. Контроль типов

Правила контроля типов в языке С-ы- появились как результат опыта работы с С with Classes. Все вызовы функций проверяются во время компиляции. Проверку последних аргументов можно отменить, дав явное указание в объявлении функции. Это необходимо для функции printf () из библиотеки С:

int printf(const char* . . .) ; принимаются любые аргументы после

начальной символьной строки

...

printf( date: %s %d 19%d\n , month,day,year); может, и правильно

Было предложено несколько механизмов контроля типов. Полный обход системы контроля типов с помощью многоточия являлся самым радикальным и наименее рекомендуемым. Перегрузка имен функций (см. раздел 3.6.1) и аргументы по умолчанию [Stroustrup,1986] (см. раздел 2.12.2) дали возможность сделать вид, что имеется одна функция, принимающая разные множества аргументов, при этом не приходилось жертвовать безопасностью типов.

Кроме того, я спроектировал систему потокового ввода/вывода, дабы продемонстрировать, что ослабление контроля типов необязательно даже в этом случае (см. раздел 8.3.1). Так, запись

cout << дата: <<month<< <<day<< 19 year<<\n;

является безопасной версией примера, приведенного выше.

Я считал и считаю до сих пор, что контроль типов - это, скорее, практический инструмент, а не самоцель. Важно понимать: устранение из программы всех до единого нарушений согласованности типов не гарантирует ни правильности профаммы, ни даже того, что она не перестанет работать (причина - использование объекта противоречит его определению). Например, случайный электрический импульс может кардинально изменить значение бита памяти. Считать небезопасное использование типов и крах профаммы эквивалентными явлениями - безответственно и неправильно. Это то же самое, как не видеть разницы между зависанием



компьютера и такими катастрофами, как крушение самолета, обрыв телефонного кабеля или авария на АЭС.

Надежность системы зависит от всех ее элементов, и нельзя возлагать ответственность за ошибку только на какой-то один. Мы пытаемся проектировать важные системы так, чтобы ни отдельная ошибка, ни даже множество ошибок не приводили к полному краху. Ответственность за целостность системы лежит на людях, которые ее создавали. В частности, безопасное использование типов - не замена тестированию, хотя оно может оказать существенную помощь при подготовке системы к тестированию. Ругать язык программирования за тот или иной сбой в системе, даже чисто программной, - значит не понимать сути предмета (см. также раздел 16.2).

3.11. Второстепенные возможности

При переходе от С with Classes к С++ было добавлено несколько второстепенных возможностей.

3.11.1. Комментарии

Из второстепенных возможностей самой заметной было введение комментариев в стиле BCPL:

int а; /* явно завершающийся комментарий в стиле С */

int Ь; комментарий в стиле BCPL, действующий до конца строки

Допустимы оба вида комментариев, поэтому программист может выбирать тот, что ему больше по душе. Я предпочитаю однострочные комментарии а-ля BCPL. Поводом для введения комментариев, начинающихся с , было то, что изредка я делал глупые ошибки, забывая закончить С-комментарий, а иногда добавление трех лишних символов делало этот комментарий слишком длинным, не помещавшимся на одной строке экрана. Еще я заметил, что / / удобнее, чем / * для комментирования коротких участков кода.

Скоро обнаружилось, что добавление / / не вполне совместимо с С. Так, выражение

X = а * разделить на */Ь

в С++ означает х=а, а в С - х=а/Ь. Но и тогда, и сейчас большинство программистов на С не считают, что на практике такое расхождение может составлять про-бле,му.

3.11.2. Нотация для конструкторов

Название функция new для конструктора всегда было источником путаницы, поэтому были введены именованные конструкторы. Одновременно появилось разрешение явно использовать конструкторы в выражениях:

complex i = complex(О,1);

complex operator+(complex a, complex b)



void X.set(X arg) { a = arg.a; }; пока все корректно

return complex(а.re+b.re, a.im+b.im);

Выражение вида complex (x, у) - это явный вызов конструктора класса complex.

Чтобы уменьшить число ключевых слов, я решил не пользоваться явным синтаксисом вроде

class X {

constructor{) ; destructor() ; . . .

Вместо этого был выбран декларативный синтаксис, лучше отражающий характер использования конструкторов:

class X {

X () ; конструктор

-ХО; деструктор (в С оператор -- означает дополнение)

...

Явный вызов конструкторов в выражениях оказался очень полезным, но явился причиной многих проблем при синтаксическом анализе С++-программ. В С with Classes функции new () и delete () по умолчанию считались public. Эта аномалия была устранена таким образом, чтобы конструкторы и деструкторы подчинялись тем же правилам контроля доступа, что и обычные функции. Например:

class Y {

Y(); закрытый конструктор ...

Y а; ошибка: нет доступа к закрытому члену Y::Y{)

В результате появились многие полезные приемы, основанные на идее контроля над операциями путе.м сокрытия функций, которые их выполняют (см. раздел 11.4).

3.11.3. Квалификация

в с with Classes точка использовалась для обозначения принадлежности к классу, а также для выбора члена конкретного объекта. Подчас из-за этого возникали неоднозначные конструкции. Вот пример:

class X {

int а; public:

void set(X);



1 ... 27 28 29 [ 30 ] 31 32 33 ... 144

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