Главная » Просмотр файлов » Б. Страуструп - Язык программирования С++

Б. Страуструп - Язык программирования С++ (1119446), страница 90

Файл №1119446 Б. Страуструп - Язык программирования С++ (Б. Страуструп - Язык программирования С++) 90 страницаБ. Страуструп - Язык программирования С++ (1119446) страница 902019-05-09СтудИзба
Просмтор этого файла доступен только зарегистрированным пользователям. Но у нас супер быстрая регистрация: достаточно только электронной почты!

Текст из файла (страница 90)

Если цельсостоит в том, чтобы разработать структуру, в которую последующие программисты (или вы сами черезнеделю) смогут встраивать свои программы, то именно виртуальные функции и предлагают элегантныйспособ решения, а защищенные члены могут быть полезны при его реализации.В качестве примера рассмотрим простой шаблон типа, определяющий буфер:template<class T>class buffer {// ...void put(T);T get();};Если реакция на переполнение и обращение к пустому буферу, "запаяна" в сам класс, его применениебудет ограничено.

Но если функции put() и get() обращаются к виртуальным функциям overflow() иunderflow() соответственно, то пользователь может, удовлетворяя своим нуждам, создать буфераразличных типов:template<class T>class buffer {//...virtual int overflow(T);virtual int underflow();void put(T);// вызвать overflow(T), когда буфер полонT get();// вызвать underflow(T), когда буфер пуст};template<class T>class circular_buffer : public buffer<T> {//...int overflow(T);// перейти на начало буфера, если он полонint underflow();};template<class T>class expanding_buffer : public buffer<T> {//...int overflow(T);// увеличить размер буфера, если он полонint underflow();};Этот метод использовался в библиотеках потокового ввода-вывода ($$10.5.3).12.2.4 Отношения принадлежностиЕсли используется отношение принадлежности, то существует два основных способа представленияобъекта класса X:[1]Описать член типа X.319Бьерн Страуструп.[2]Язык программирования С++Описать член типа X* или X&.Если значение указателя не будет меняться и вопросы эффективности не волнуют, эти способыэквивалентны:class X {//...public:X(int);//...};class C {X a;X* p;public:C(int i, int j) : a(i), p(new X(j)) { }~C() { delete p; }};В таких ситуациях предпочтительнее непосредственное членство объекта, как X::a в примере выше,потому что оно дает экономию времени, памяти и количества вводимых символов.

Обратитесь также к$$12.4 и $$13.9.Способ, использующий указатель, следует применять в тех случаях, когда приходится перестраиватьуказатель на "объект-элемент" в течении жизни "объекта-владельца". Например:class C2 {X* p;public:C(int i) : p(new X(i))~C() { delete p; }X* change(X* q){X* t = p;p = q;return t;}};{ }Член типа указатель может также использоваться, чтобы дать возможность передавать "объектэлемент" в качестве параметра:class C3 {X* p;public:C(X* q) : p(q) {// ...}}Разрешая объектам содержать указатели на другие объекты, мы создаем то, что обычно называется"иерархия объектов". Это альтернативный и вспомогательный способ структурирования по отношению киерархии классов. Как было показано на примере аварийного движущегося средства в $$12.2.2, частоэто довольно тонкий вопрос проектирования: представлять ли свойство класса как еще один базовыйкласс или как член класса.

Потребность в переопределении следует считать указанием, что первыйвариант лучше. Но если надо иметь возможность представлять некоторое свойство с помощьюразличных типов, то лучше остановиться на втором варианте. Например:class XX : public X { /*...*/ };class XXX : public X { /*...*/ };void f(){320Бьерн Страуструп.Язык программирования С++C3* p1 = new C3(new X);C3* p2 = new C3(new XX);C3* p3 = new C3(new XXX);//...// C3 "содержит"// C3 "содержит"// C3 "содержит"XXXXXX}Приведенные определения нельзя смоделировать ни с помощью производного класса C3 от X, ни спомощью C3, имеющего член типа X, поскольку необходимо указывать точный тип члена.

Это важнодля классов с виртуальными функциями, таких, например,как класс Shape ($$1.1.2.5), и для классаабстрактного множества ($$13.3).Заметим, что ссылки можно применять для упрощения классов, использующих члены-указатели, если втечение жизни объекта-владельца ссылка настроена только на один объект, например:class C4 {X& r;public:C(X& q) : r(q) { }// ...};12.2.5 Принадлежность и наследованиеУчитывая сложность важность отношений наследования, нет ничего удивительного в том, что часто ихнеправильно понимают и используют сверх меры. Если класс D описан как общий производный откласса B, то часто говорят, что D есть B:class B { /* ...

*/ ;class D : public B /* ... */ };// D сорта BИначе это можно сформулировать так: наследование – это отношение "есть", или, более точно дляклассов D и B, наследование - это отношение D сорта B. В отличие от этого, если класс D содержит вкачестве члена другой класс B, то говорят, что D "имеет" B:class D { // D имеет B// ...public:B b;// ...};Иными словами, принадлежность - это отношение "иметь" или для классов D и B просто: D содержит B.Имея два класса B и D, как выбирать между наследованием и принадлежностью? Рассмотрим классысамолет и мотор.Новички обычно спрашивают: будет ли хорошим решением сделать класс самолетпроизводным от класса мотор.

Это плохое решение, поскольку самолет не "есть" мотор, самолет"имеет" мотор. Следует подойти к этому вопросу, рассмотрев, может ли самолет "иметь" два илибольше моторов. Поскольку это представляется вполне возможным (даже если мы имеем дело спрограммой, в которой все самолеты будут с одним мотором), следует использовать принадлежность, ане наследование.

Вопрос "Может ли он иметь два..?" оказывается удивительно полезным во многихсомнительных случаях. Как всегда, наше изложение затрагивает неуловимую сущностьпрограммирования. Если бы все классы было так же легко представить, как самолет и мотор, то былобы просто избежать и тривиальных ошибок типа той, когда самолет определяется как производное откласса мотор. Однако, такие ошибки достаточно часты, особенно у тех, кто считает наследование ещеодним механизмом для сочетания конструкций языка программирования. Несмотря на удобство илаконичность записи, которую предоставляет наследование, его надо использовать только длявыражения тех отношений, которые четко определены в проекте.

Рассмотрим определения:class B {public:virtual void f();void g();};321Бьерн Страуструп.class D1 {public:B b;void f();};void h1(D1* pd){B* pb = pd;pb = &pd->b;pb->q();pd->q();pd->b.q();pb->f();pd->f();}Язык программирования С++// D1 содержит B// не переопределяет b.f()// ошибка: невозможно преобразование D1* в B*// вызов B::q// ошибка: D1 не имеет член q()// вызов B::f (здесь D1::f не переопределяет)// вызов D1::fОбратите внимание, что в этом примере нет неявного преобразования класса к одному из егоэлементов, и что класс, содержащий в качестве члена другой класс, не переопределяет виртуальныефункции этого члена.

Здесь явное отличие от примера, приведенного ниже:class D2 : public B {public:void f();};void h2(D2* pd){B* pb = pd;pb->q();pd->q();pb->f();pd->f();}// D2 есть B// переопределение B::f()//////////нормально: D2* неявно преобразуется в B*вызов B::qвызов B::qвызов виртуальной функции: обращение к D2::fвызов D2::fУдобство записи, продемонстрированное в примере с классом D2, по сравнению с записью в примере склассом D1, является причиной, по которой таким наследованием злоупотребляют. Но следуетпомнить, что существует определенная плата за удобство записи в виде возросшей зависимости междуB и D2 (см. $$12.2.3).

В частности, легко забыть о неявном преобразовании D2 в B. Если только такиепреобразования не относятся к семантике ваших классов, следует избегать описания производногокласса в общей части. Если класс представляет определенное понятие, а наследование используетсякак отношение "есть", то такие преобразования обычно как раз то, что нужно.Однако, бывают такие ситуации, когда желательно иметь наследование, но нельзя допускатьпреобразования. Рассмотрим задание класса cfield (controled field - управляемое поле), который,помимо всего прочего, дает возможность контролировать на стадии выполнения доступ к другомуклассу field. На первый взгляд кажется совершенно правильным определить класс cfield какпроизводный от класса field:class cfield : public field {// ...};Это выражает тот факт, что cfield, действительно, есть сорта field, упрощает запись функции, котораяиспользует член части field класса cfield, и, что самое главное, позволяет в классе cfield переопределятьвиртуальные функции из field.

Загвоздка здесь в том, что преобразование cfield* к field*, встречающеесяв определении класса cfield, позволяет обойти любой контроль доступа к field:void q(cfield* p){*p = "asdf";// обращение к field контролируется322Бьерн Страуструп.field* q = p;*q = "asdf";Язык программирования С++////////функцией присваивания cfield:p->cfield::operator=("asdf")неявное преобразование cfield* в field*приехали! контроль обойден}Можно было бы определить класс cfield так, чтобы field был его членом, но тогда cfield не можетпереопределять виртуальные функции field.

Лучшим решением здесь будет использованиенаследования со спецификацией private (частное наследование):class cfield : private field { /* ... */ }С позиции проектирования, если не учитывать (иногда важные) вопросы переопределения, частноенаследование эквивалентно принадлежности. В этом случае применяется метод, при котором классопределяется в общей части как производный от абстрактного базового класса заданием егоинтерфейса, а также определяется с помощью частного наследования от конкретного класса,задающего реализацию ($$13.3). Поскольку наследование, используемое как частное, являетсяспецификой реализации, и оно не отражается в типе производного класса, то его иногда называют"наследованием по реализации", и оно является контрастом для наследования в общей части, когданаследуется интерфейс базового класса и допустимы неявные преобразования к базовому типу.Последнее наследование иногда называют определением подтипа или "интерфейснымнаследованием".Для дальнейшего обсуждения возможности выбора наследования или принадлежности рассмотрим, какпредставить в диалоговой графической системе свиток (область для прокручивания в ней информации),и как привязать свиток к окну на экране.

Потребуются свитки двух видов: горизонтальные ивертикальные. Это можно представить с помощью двух типов horizontal_scrollbar и vertical_scrollbar илис помощью одного типа scrollbar, который имеет аргумент, определяющий, является расположениевертикальным или горизонтальным. Первое решение предполагает, что есть еще третий тип, задающийпросто свиток - scrollbar, и этот тип является базовым классом для двух определенных свитков.

Второерешение предполагает дополнительный аргумент у типа scrollbar и наличие значений, задающих видсвитка. Например, так:enum orientation { horizontal, vertical };Как только мы остановимся на одном из решений, определится объем изменений, которые придетсявнести в систему. Допустим, в этом примере нам потребуется ввести свитки третьего вида.

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

Характеристики

Список файлов книги

Свежие статьи
Популярно сейчас
А знаете ли Вы, что из года в год задания практически не меняются? Математика, преподаваемая в учебных заведениях, никак не менялась минимум 30 лет. Найдите нужный учебный материал на СтудИзбе!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает - и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе "Студизба"
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Популярные преподаватели
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
6374
Авторов
на СтудИзбе
309
Средний доход
с одного платного файла
Обучение Подробнее