C++: библиотека программиста



Download 1,95 Mb.
Pdf ko'rish
bet95/144
Sana24.02.2022
Hajmi1,95 Mb.
#223123
TuriРеферат
1   ...   91   92   93   94   95   96   97   98   ...   144
Bog'liq
C -Eldjer-Djeff-for-Real-Programmers-RUS-www.itlibitum.ru

 
167 
иерархий, поскольку при совпадении сигнатуры в двух базовых классах компилятор начнет кричать 
«Караул, неоднозначность!». 
class foo { ... }; 
class bar : public foo { ... }; 
class banana : public bar { ... }; 
void fn(bar&); 
void fn(foo&); 
fn(*(new banana));
// Неоднозначность! Ха-ха-ха! 
Компиляторы обожают подобные шутки, поскольку они могут ждать и не сообщать об ошибке до тех 
пор, пока им не встретится заветное сочетание типов. Если бы существовала перегрузка 
fn()
для 
аргумента 
banana&
, никаких проблем не возникло бы — компилятор всегда предпочитает точное 
совпадение преобразованию. Но тогда пропадает весь смысл группировки посредством 
автоматического преобразования к базовому классу. 
Отделение типов от иерархии классов 
Второй подход сопровождается мучительными логическими построениями. Перед выполнением 
передачи аргументы преобразуются от специализированных типов к более универсальным. Например, 
при любой операции, в которой учавствует комплексное число (
Complex
), второй аргумент заранее 
преобразуется к типу 
Complex
. Тем самым из матрицы фактически исключается целая строка и 
столбец. Если ни один из аргументов не является комплексным, мы ищем среди них вещественный 
(
Real
); если он будет найден, второй аргумент также преобразуется в 
Real
. Если не будут найдены ни 
Complex
, ни 
Real
, ищем 
Rational
и т.д. Подобная иерархия преобразований — от 
Integer
(или чего 
угодно) к 
Rational
, затем 
Real
и 
Complex
— не совпадает с иерархией классов, поскольку было бы 
глупо порождать легкий 
Integer
от тяжеловесного 
Complex
. Кстати, весьма интересный вопрос: 
почему иерархии типов (в данном случае числовых) часто плохо укладываются в иерархии классов, 
основанных на общих свойствах? 
Это еще не все 
Конечно, только что описанная методика передачи имеет некоторые недостатки. Во-первых, 
производные классы не удается нормально инкапсулировать, поскольку их все приходится перечислять 
в интерфейсах диспетчерских функций базового класса. В сущности, чтобы не вводить код типа, 
видимый широкой публике, мы выставили на всеобщее обозрение все производные типы — не очень 
хороший компромисс. Во-вторых, что произойдет с оператором вроде 
+=
? Если в программе 
встречается 
Integer+=Complex
, результат будет иметь тип 
Complex
, а мы пока не располагаем 
средствами для преобразования типа «на месте». 
В главах 11 и 12 обе проблемы будут решены для гомоморфных иерархий классов, хотя приведенные 
методики обобщаются и для других ситуаций (скажем, для упомянутой выше проблемы с классами 
Event/View
). А пока лишь скажу, что описанные в этой главе приемы приносят непосредственную 
пользу в тех ситуациях, когда на первое место выходит быстродействие, а не инкапсуляция. Два 
перехода по v-таблицам почти всегда работают быстрее традиционных подходов. 
Наконец, не удивляло ли вас то, как наши функции возвращали 
Number&

Number& Integer::operator+(const Integer& n) 

// 
Ниже приведен псевдокод 
if (i + n.i слишком велико для int) { 
return 
ЦелоеСПовышенной точностью 

else return Integer(i + n.i); 

Возвращение ссылок на переменную величину — дело опасное. Многие компиляторы пускают в 
расход возвращаемую величину до того, как вам удастся ее использовать. Выделение памяти под 


 168 
возвращаемый объект оператором new (вместо стека) решает проблему, поскольку величина заведомо 
остается жить после завершения функции. Но тогда возникают проблемы с управлением памятью — 
когда и как удалять возвращаемую величину? Чтобы решить ее, нам понадобится материал глав 11 и 
12, а также одна из методик управления памятью (скажем, подсчет ссылок), рассматриваемых в 
последней части книги. 
Итак, приведенной в этой главе информации хватит для решения простых проблем (например, 
связанных с событиями и видами), но она лишь закладывает основу для построения более общих 
решений. 


Производящие 
функции и 
объекты классов 
В предыдущей главе мы стролкнулись с гомоморфными иерархиями классов и с головой погрузились 
во множественную передачу. В этой главе мы продолжим исследовать царство иерархий классов, 
рассматривая объекты классов и сопутствующие темы. 
Примеры из предыдущей главы обладали одним недостатком — все производные классы были видны 
клиентам. Но если производные классы погребены в файлах .cpp на глубине нескольких метров, как 
клиенту создавать экземпляры этих спрятанных классов? Этой теме посвящено начало главы. 
Производящей функцией (factory function) называется функция, которая инкапсулирует применение 
оператора new для создания экземпляров класса. Знатоки С++ обычно сходятся на том, что 
производящие функции — Хорошая Вещь, и вскоре вы поймете почему. Вы оказались на семинаре с 
коктейлями и хотите найти хорошую тему для разговора? Поднимите стакан и небрежно упомяните о 
том, как производящие функции выручили вас в трудную минуту. 
Во многих программах нам хотелось бы в процессе их выполнения сделать нечто, не поддерживаемое 
динамической моделью С++ (например, запросить у объекта его класс). Для этой цели существует 
предложенный стандарт RTTI (Run Time Type Information, Динамическая информация о типе), но по 
причинам, о которых будет сказано ниже, его вряд ли можно считать универсальным или хотя бы 
полезным средством. Вместо этого мы рассмотрим нестандартные решения, основанные на концепции 
объектов классов, в том числе особый случай — представителей классов. 
Производящие функции 
Предположим, вы согласились, что гомоморфизм — это хорошо, и тут же сотворили свою собственную 
гомоморфную иерархию классов. 
// В файле Grandpa.h 
class Grandpa { ... }; 
// Скрыто в файле Grandpa.cpp 
class Dad : public Grandpa { ... }; 
class AuntieEm : public Grandpa { ... }; 
// Где-то в нашей программе 
#include “Grandpa.h” 
Grandpa* g = new ... 
// Стоп! Как создать «папу»? 
Допустим, с позиций биологии все понятно, но мы говорим о С++, не правда ли? Проблема 
заключается в том, что мы надежно изолировали «папу» (
Dad
) от внешнего мира — по крайней мере 
для любого кода, расположенного за пределами файла 
Grandpa.cpp
. Замечательный интерфейс 

Download 1,95 Mb.

Do'stlaringiz bilan baham:
1   ...   91   92   93   94   95   96   97   98   ...   144




Ma'lumotlar bazasi mualliflik huquqi bilan himoyalangan ©hozir.org 2024
ma'muriyatiga murojaat qiling

kiriting | ro'yxatdan o'tish
    Bosh sahifa
юртда тантана
Боғда битган
Бугун юртда
Эшитганлар жилманглар
Эшитмадим деманглар
битган бодомлар
Yangiariq tumani
qitish marakazi
Raqamli texnologiyalar
ilishida muhokamadan
tasdiqqa tavsiya
tavsiya etilgan
iqtisodiyot kafedrasi
steiermarkischen landesregierung
asarlaringizni yuboring
o'zingizning asarlaringizni
Iltimos faqat
faqat o'zingizning
steierm rkischen
landesregierung fachabteilung
rkischen landesregierung
hamshira loyihasi
loyihasi mavsum
faolyatining oqibatlari
asosiy adabiyotlar
fakulteti ahborot
ahborot havfsizligi
havfsizligi kafedrasi
fanidan bo’yicha
fakulteti iqtisodiyot
boshqaruv fakulteti
chiqarishda boshqaruv
ishlab chiqarishda
iqtisodiyot fakultet
multiservis tarmoqlari
fanidan asosiy
Uzbek fanidan
mavzulari potok
asosidagi multiservis
'aliyyil a'ziym
billahil 'aliyyil
illaa billahil
quvvata illaa
falah' deganida
Kompyuter savodxonligi
bo’yicha mustaqil
'alal falah'
Hayya 'alal
'alas soloh
Hayya 'alas
mavsum boyicha


yuklab olish