Информационный сайт

 

Реклама
bulletinsite.net -> Книги на сайте -> Программисту -> Мизрохи С.В. -> "Turbo Pascal и объектно-ориентированное программирование" -> 50

Turbo Pascal и объектно-ориентированное программирование - Мизрохи С.В.

Мизрохи С.В. Turbo Pascal и объектно-ориентированное программирование — М.: Финансы и статистика , 1992. — 192 c.
ISBN 5-279-00903-2
Скачать (прямая ссылка): efektispolzc2000.djvu
Предыдущая << 1 .. 44 45 46 47 48 49 < 50 > 51 52 53 54 55 56 .. 105 >> Следующая

class Basel { . . class Base2 { private:
void dolt ();
};
};
Il To же, что и выше.
11 Это теперь закрытая функция.
¦¦Il
Классы и функции
class Derived: public Basel, public Base2
{.-.}; I1 To же, Derived d;
int і - d.doItO; Il Ошибка
Il To же, что и выше.
Il Ошибка! По-прежнему неоднозначность!
Вызов dolt продолжает оставаться неоднозначным, несмотря на то что доступными являются только функции в Basel! Тот факт, что только Basel: : dolt возвращает значение, которое может быть использовано для инициализации int, также не принимается во внимание - вызов функции остается неоднозначным. Если вы хотите вызвать эту функцию, то просто должны указать, dolt какого класса вам нужна.
Как и в большинстве случаев, когда правила С++ кажутся неразумными, существует веская причина, по которой для однозначности вызова функций базовых классов не принимаются в расчет ограничения доступа. Здесь все сводится к следующему: изменение доступности члена класса не должно менять смысла программы.
Например, предположим, что в предыдущем примере вы принимаете в расчет ограничения доступа. Выражение d.dolt () тогда будет интерпретировано как вызов Basel: : dolt, поскольку функция в Base2 недоступна. Теперь предположим, что Basel изменился таким образом, что его функция dolt вместо открытой стала защищенной, a Base2 был модифицирован так, что его функция вместо закрытой стала открытой.
Весьма неожиданно то же самое выражение - d. dolt () - станет осуществлять совершенно другой функциональный вызов, даже несмотря на то, что ни код вызова функции, ни вызывающие функции не были изменены! Теперь уже это кажется неразумным, а у компилятора нет никакой возможности выдать даже предупреждение. Поэтому, рассматривая варианты, вы можете решить, что необходимость явного разрешения неоднозначности при доступе к наследуемым членам не является настолько неоправданной, как это представлялось вначале.
При том, что способов написания программ и библиотек, изобилующих потенциальными неоднозначностями, существует великое множество, - что остается делать хорошему разработчику программного обеспечения? В основном нельзя упускать из виду указанного обстоятельства. Практически невозможно искоренить все потенциальные источники неоднозначности, особенно при комбинировании независимо написанных библиотек (см. также правило 28), но понимание ситуаций, часто ведущих к потенциальным неоднозначностям, дает вам хорошие шансы на уменьшение их количества.
Предположим, вам хочется написать шаблон класса Array, который генерирует классы, ведущие себя подобно встроенным в С++ массивам за одним исключением: они осуществляют проверку выхода индекса за границы. Одна из возникающих
Правило 27. Явно запрещайте использование нежелательных функций-членов, создаваемых компилятором по умолчанию
Правило 27
113
проблем - как запретить присваивание объектов Array, поскольку в С++ присваивание запрещено для массивов:
double valuesl[10]; double values2[10]; valuesl = values2; // Ошибка!
Для большинства функций это не составляет проблемы. Если функция вам не нужна, вы просто не обтэявите ее в классе. Однако оператор присваивания относится к избранным функциям-членам: если вы не пишете их сами, услужливый помощник С++ всегда напишет их за вас (см. правило 45). Что делать?
Решение заключается в том, чтобы объявить функцию (в данном случае I operator=) закрытой. Объявляя функцию-член явным образом, вы не даете компилятору генерировать свои собственные версии, а делая функцию закрытой, вы не позволяете ее вызвать.
Однако это не защищает вас от ее случайного использования: члены класса и дружественные функции все же могут вызвать вашу закрытую функцию. Конечно, это справедливо только в том случае, если вы не опустили ее определение. Тогда при неумышленном вызове функции вы получите ошибку в момент компоновки (см. правило 46).
Для Array ваше определение шаблона начиналось бы следующим образом:
template<class Т> class Array { private:
II Не определяйте эту функцию! Array& operator=(const Array& rhs) ;
};
Теперь, если пользователь вознамерится выполнить присваивание объектов Array, компилятор пресечет эту попытку, а если вы по неосторожности попытаетесь сделать это в функции-члене или дружественной функции, начнет роптать компоновщик.
Не делайте на основании этого примера вывод, что данное правило применимо только к оператору присваивания. Совсем нет. Оно действует в отношении каждой генерируемой компилятором функции, описанной в правиле 45. На практике вы обнаружите, что функциональное подобие между оператором присваивания и конструктором копирования (см. правила 11 и 16) практически всегда означает, что когда вы хотите запретить использование одного, вам необходимо запретить ^ использование другого.
Правило 28. Расчленяйте J
глобальное пространство имен
Самая серьезная проблема, касающаяся глобальной области видимости, связана I с гем, что эта область только одна. В написании большого программного продукта 1
114
¦вин
Классы и функции
участвует огромное количество людей, каждый из которых создает имена в одной и той же области видимости, что с неизбежностью ведет к конфликтам имен. Например, заголовочный файл libraryl. h может определять ряд констант, включая следующие:
Предыдущая << 1 .. 44 45 46 47 48 49 < 50 > 51 52 53 54 55 56 .. 105 >> Следующая
Реклама
Авторские права © 2009 AdsNet. Все права защищены.
Rambler's Top100