Это рассуждение можно подкрепить некоторым математическим анализом. Напомним условие корректности процедуры из лекции 11 об утверждениях:
{prer (xr) and INV} Bodyr {postr (xr) and INV}.
Для целей нашего обсуждения его можно немного упростить, оставив только часть, относящуюся к инвариантам классов, опустив аргументы и используя в качестве индекса имя класса
[A-CORRECT]
{INVA} rA {INVA}
Содержательно это означает, что всякое выполнение процедуры
[B-CORRECT]
{INVB} rB {INVB}
Напомним, что инварианты накапливаются при движении вниз по структуре наследования, так что
Рис. 14.14. Версия родителя может не удовлетворять новому инварианту
Напомним, например, как
consistent_balance: deposits_listltotal - withdrawals_listltotal = current_balance
Из-за этого, возможно, придется переопределить некоторые из процедур класса
Предположим теперь, что к объекту типа
Такой результат - объект, не удовлетворяющий инварианту своего класса, т.е. основным, универсальным ограничениям на все объекты такого вида - является одним из самых страшных событий, которые могут случиться во время выполнения программы. Если такая ситуация может возникнуть, то нечего надеяться на верный результат вычисления.
Суммируем: статическое связывание является либо оптимизацией, либо ошибкой. Если его семантика совпадает с семантикой динамического связывания (как в случаях (1) и (2)), то оно является оптимизацией, которую может выполнить компилятор. Если у него другая семантика, то это ошибка.
Подход языка С++ к связыванию
Учитывая широкое распространение и влияние языка С++ на другие языки, нужно разъяснить, как в нем решаются некоторые из обсуждаемых здесь вопросов.
Соглашения, принятые в С++, кажутся странными. По умолчанию связывание является статическим. Чтобы процедура (в терминах С++ - функция или метод) связывалась динамически, она должна быть специально объявлена как виртуальная (virtual).
Это означает, что приняты два решения:
1 Сделать программиста ответственным за выбор статического или динамического связывания.
2 Использовать статическое связывание в качестве предопределенного.
Оба нарушают ОО-разработку ПО, но в различной степени: (1) можно попробовать объяснить, а (2) защищать трудно.
По сравнению с подходом этой книги (1) ведет к другому пониманию того, какие задачи должны выполняться людьми (разработчиками ПО), а какие - компьютерами (более точно, компиляторами). Это та же проблема, с которой мы столкнулись при обсуждении автоматического распределения памяти. Подход С++ продолжает традиции C и дает программисту полный контроль над тем, что случится во время выполнения, будь то размещение объекта или вызов процедуры. В отличие от этого, в духе ОО-технологии стремление переложить на плечи компилятора все утомительные задачи, выполнение которых вручную приводит к ошибкам, и для которых имеются подходящие алгоритмы. В крупном масштабе и на большом промежутке времени компиляторы всегда справятся с работой лучше.
Вильям Л Саймон , Вильям Саймон , Наталья Владимировна Макеева , Нора Робертс , Юрий Викторович Щербатых
Зарубежная компьютерная, околокомпьютерная литература / ОС и Сети, интернет / Короткие любовные романы / Психология / Прочая справочная литература / Образование и наука / Книги по IT / Словари и Энциклопедии