|
Программирование >> Оптимизация возвращаемого значения
в начале этого раздела. Вы также должны остерегаться неприятностей, связанных с массивами (см. правило 3); □ попытаться найти абстрактный класс, который находится более высоко в иерархии библиотеки и делает большую часть того, что вам нужно, а затем выполнить наследование от этого класса. Конечно, подходящего класса может и не быть, и даже если такой класс существует, вам может потребовать ся повторить значительную часть работы, которую вы уже сделали при реализации реального класса, функциональность которого хотите расширить; □ реализовать новый класс при помощи библиотечного класса, от которого вы бы хотели наследовать. Например, можно включить объект библиотечного класса в качестве элемента данных, а затем реализовать интерфейс библиотечного класса в вашем новом классе: class Window { Это библиотечный класс, public: virtual void resize(int newWidth, int newHeight) ; virtual void repaint{) const; int width{) const; int height{) const; class SpecialWindow { Это класс, который вы хотите public: сделать наследником класса Window. реализация невиртуальных функций intwidthO const { return w.width() ; } int height{) const { return w.height{); } реализация унаследованных виртуальных функций virtual void resize{int newWidth, int newHeight) ; virtual void repaint () const; private: Window w; Эта стратегия требует обновлять ваш класс при каждом обновлении версии библиотечного класса, от которого он зависит. Вы также будете вынуждены отказаться от возможности переопределять объявленные в библиотечном классе виртуальные функции, так как нельзя переопределять не унаследованные виртуальные функции; □ примириться с тем, что есть. Использовать реальный класс из библиотеки и изменить программу так, чтобы этого класса было достаточно. Писать функции - не члены класса, обеспечивающие функциональность, которую выхотите, но не можете добавить к классу. Пол5енная в результате программа может быть не так эффективна, не так переносима и расширяема, как вам бы этого хотелось, но по крайней мере работоспособна. Ни один из этих вариантов не является особенно привлекательным, поэтому вам придется выбирать наименьшее из зол. Это не слишком весело, но уж так устроен мир. Чтобы в будущем облегчить жизнь себе (и остальным), выражайте недовольство создателям библиотек, которые вы считаете плохо разработанными. В случае удачи (и большого числа жалоб пользователей), структура этих библиотек может со временем улучшиться. Каким бы ни был ваш выбор, основное правило остается в силе: нетерминальные классы должны быть абстрактными. Вы не всегда сможете следовать ему, работая с чужими библиотеками, но в коде, которым управляете вы сами, соблюдение этого правила принесет вам дивиденды в виде надежности, жив5ести, понятности и расширяемости ваших программ. Правило 34. Умейте использовать в одной программе С и С++ Проблемы, возникающие при создании программы, часть которой написана на С++, а часть на С, во многом совпадает с трудностями, с которыми вы сталкиваетесь, пытаясь сшить программу из объектных файлов, сгенерированных несколькими компиляторами С. Не существует способа объединить такие файлы, если различные компиляторы не согласуются по параметрам, зависящим от реализации, например размеру чисел типа int и double и механизму передачи параметров при вызове функции. Практические аспекты разработки программ с помощью нескольких компиляторов почти полностью игнорируются при стандартизации языка, поэтому единственный надежный способ проверить, можно ли объединять в одной программе объектные файлы, созданные при помощи компиляторов А и В, - получить от поставщиков А и В подтверждение, что их продукты дают совместимый выход. Это верно и для программ, созданных при помощи С и С++, поэтому перед тем, как попытаться сочетать С и С++ в одной программе, убедитесь, что ваши компиляторы С и С++ генерируют совместимые объектные файлы. После этого вам нужно будет рассмотреть еще четыре аспекта: коррекцию имен, инициализацию статических объектов, динамическое выделение памяти и совместимость структур данных. Коррекция имен Как вы, наверное, уже знаете, коррекция имен (паше mangling) - это процесс, во время которого компиляторы С++ дают каждой функции в программе уникальное имя. В языке С такой процесс не нужен, поскольку нельзя перегружать имена функций, но почти любая программа С++ содержит несколько функций с одним и тем же именем. (Рассмотрим, например, библиотеку iostream, в которой объявляются несколько версий функций operator<< и operator .) Перегрузка несовместима со многими компоновщиками, так как они обычно скептически относятся к нескольким функциям с одним именем. Коррекция имен является уступкой компоновщикам; в частности их требованию, чтобы все имена функций были уникальными. Пока вы работаете только с С++, коррекция имен вряд ли будет вас беспокоить. Если имеется функция drawLine, имя которой компилятор корректирует как xyzzy, то вы будете всегда использовать имя drawLine, и вам не будет дела до того, что в объектных файлах она называется xyzzy. Ситуация будет совсем другой, если функция drawLine находится в библиотеке С. В этом случае ваш исходный файл, вероятно, будет включать заголовочный файл, содержащий такое объявление: void drawLine (int xl, int yl, int x2 , int у2) ; a код, как обычно, будет содержать вызовы функции drawLine. Каждый такой вызов будет транслироваться компилятором в вызов скорректированного имени функции, поэтому если записать следующее: drawLine{a, b, с, d) ; Вызов нескорректированного имени функции. ТО объектные файлы будут содержать соответствующий вызов функции: xyzzy{a, b, с, d) ; Вызов скорректированного / / имени функции. Но если drawLine является функцией С, то объектный файл (или архив, или динамически подключаемая библиотека и т.д.) будет содержать скомпилированную версию функции drawLine с тем же именем drawLine, корректировка имени не будет выполняться. Когда вы попытаетесь скомпоновать объектные файлы вместе, то получите сообщение об ошибке, потому что компоновщик ищет функцию с именем xyzzy, а такой функции не существует. Чтобы решить проблему, вам нужен какой-то способ сообщить компилятору С++, что не нужно выполнять корректировку определенных имен функций. Это не нужно будет делать для функций, написанных на других языках, будь то С, ассемблер, Fortran, Lisp, Forth или какой-то другой язык. (Включая и Cobol, но что вам до этого?) В конце концов, если вы вызываете функцию С с именем drawLine, она на самом деле называется drawLine, и объектный код должен содержать ссылку именно на это имя, а не на его откорректированную версию. Используйте для подавления коррекции имен директиву С++ extern С : Объявить функцию drawLine; не корректировать ее имя. extern С void drawLine (int xl, int yl, int x2 , int у2); He попадитесь в ловушку, предположив, что если есть extern С , то должен быть и extern Pascal и extern FORTRAN . Таких директив нет, по крайней мере в стандарте языка. Лучше всего рассматривать директиву extern С не как утверждение, что вызываемая функция написана на С, а как утверждение, что функция должна вызываться так, будто бы она была написана на С. (Технически, директива extern С означает, что функция должна компоноваться принятым
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |