|
Программирование >> Обобщенные обратные вызовы
Рис. 14.1. Иерархия наследования в примере 14 2 Порядок инициализации объекта х в примере 14-2 имеет следующий вид (каждый показанный ниже вызов конструктора представляет выполнение его тела): Сначала конструируются виртуальные базовые классы: конструирование vL: В1::в1() vl::vl() конструирование v2: В1::В1() В2::В2() v2::V2() Затем конструируются невиртуальные базовые классы: конструирование Dl: Dl::D1() конструирование d2: вЗ::вЗ() d2::d2() После этого конструируются члены: м1: :м1С) м2: :м2С) И наконец, выполняется конструктор X: X: :Х() Резюме Хотя основная цель данной задачи - достичь лучшего понимания порядка конструирования объектов (и их деструкции - в обратном порядке), это не мешает нам повторить одно правило, имеющее некоторое отношение к данной теме. > Рекомендация Не злоупотребляйте наследованием. Если не учитывать отношения дружбы, наследование представляет собой наиболее сильную взаимосвязь, имеющуюся в С+ + , и использовать ее следует только там, где это действительно необходимо. Более подробно этот вопрос рассмотрен в книгах [SutterOO] и [Suttcr02]. Задача 15. Потребление и злоупотребление правами доступа Сложность: 6 Кто в действительности имеет право доступа к внутренней организации вашего класса? Эта задача - о фальсификаторах, мошенниках, карманниках и ворах, а также о том, как их распознать и спастись от них. Вопрос для новичка 1. Какой код может обращаться к следующим частям класса: а) public б) protected в) private Вопрос для профессионала 2. Рассмотрим следующий заголовочный файл. Файл x.h class X { public: х() : private (l) { /*...*/ } tempiate<class т> void fС const T& t ) { /*...*/ } int ValueO { return private ; } ... private: int private ; Покажите, как произвольный вызывающий код может получить непосредственный доступ к закрытому члену класса private..: а) при помощи нестандартного и непереносимого хака ; б) при помощи переносимой и соответствующей стандарту методики. 3. Подумайте, не является ли это дырой в механизме управления правами доступа в С++ (а следовательно, дырой в инкапсуляции С++)? Решение Эта задача - о фальсификаторах, обманщиках, мошенниках и ворах... 1. Какой код имеет право доступа к следующим частям класса: а) public Воз.можность обращения к открытым членам имеет любой код. б) protected Возможность обрашения к защищенным членам имеют только функции-члены того же класса и его друзья, а также функции-члены и друзья производных классов. в) private Возможность обращения к закрытым членам имеют только функции-члены того же класса и его друзья. Это обычный ответ, и обычно это правильно. Но в этой задаче мы рассмотрим специальный случай, когда этот ответ не полон, поскольку иногда С++ предоставляет возможность законного (пусть и аморального) нарушения прав доступа к закрытым членам. 2. Рассмотрим следующий заголовочный файл ... Покажите, как произвольный вызьшающий код может получить непосредственный доступ к закрытому члену класса pri vate : а) при помощи нестандартного и непереносимого хака ; б) при помощи переносимой и соответствующей стандарту методики. Есть странная притягательность в самых трагических сценах, когда мы смотрим не отрываясь на автомобильные аварии, падающие небоскребы и... взлом кода. При попытке ответить на вопрос о том, как обратиться к закрытому члену нестандартными и непереносимыми методами, в голову приходит целый ряд идей. Вот три из них. Преступник №1: фальсификатор Метод фальсификатора состоит в том, чтобы продублировать определение фальсифицируемого класса, в которое внесены все необходимые нам изменения, например: Пример 15-1: ложь и подделка class X { вместо включения файла x.h, вручную (и незаконно) дублируем определение X и добавляем строку наподобие этой: friend :: Hi jack С х& ) ; void HijackC х& х ) { X.private. =2; Злобный смех Этот человек - фальсификатор. Запомните его хорошенько, ему нельзя доверять... Конечно, то, что сделано, - не законно. Это не законно хотя бы потому, то нарушает правило одного определения, которое гласит, что если тип (в нашем случае - х) определен более одного раза, то все его определения должны быть идентичны. Используемый же в приведенном примере объект хотя и называется X и выглядит похожим на X, но это не тот же Х, который используется остальным кодом программы. Тем не менее, такой хак будет работать на большинстве компиляторов, поскольку расположение данных объекта останется неизменным. Преступник №2: карманник Карманник сработает тихо - подменив смысл определения класса, например, следующим образом. пример 15-2: использование макромагии #define private public не законно! #include x.h void HijackC x& x ) { x.private - 2; Злобный смех Этот человек - карманник. Запомните его умелые пальцы! Конечно, то, что делает карманник, - не законно. Код из примера 15-2 непереносим по двум причинам. Не законно переопределять при помощи директивы #define зарезервированные слова.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |