- •Глава 6 посвящена понятию производных классов, которое позволяет строить
- •Раздел 3.4 главы 2. Для обозначения справочного руководства применяется
- •1991 Г.Г. (такие как множественное наследование, статические функции-члены
- •1.1 Введение
- •1.2 Парадигмы программирования
- •1.2.1 Процедурное программирование
- •1.2.5 Объектно-ориентированное программирование
- •1.5 Поддержка объектно-ориентированного программирования
- •1.5.1 Механизм вызова
- •1.5.2 Проверка типа
- •1.5.3 Множественное наследование
- •1.6 Пределы совершенства
- •2.2 Имена
- •2.3.2 Неявное преобразование типа
- •2.4 Литералы
- •2.4.4 Строки
- •2.6. Экономия памяти
- •2.6.1 Поля
- •3.1.1 Анализатор
- •3.1.2 Функция ввода
- •3.2 Сводка операций
- •3.2.3 Инкремент и декремент
- •3.2.5 Преобразование типа
- •3.2.6 Свободная память
- •3.3.2 Оператор goto
- •4.1 Введение
- •4.3.1 Единственный заголовочный файл
- •4.3.2 Множественные заголовочные файлы
- •4.4 Связывание с программами на других языках
- •4.6.3 Передача параметров
- •5.1 Введение и краткий обзор
- •5.3.1 Альтернативные реализации
- •5.3.2 Законченный пример класса
- •Vector и matrix, мы могли бы обойтись без контроля индекса при
- •5.4.5 Указатели на члены
- •5.4.6 Структуры и объединения
- •5.5.3 Свободная память
- •5.5.5 Массивы объектов класса
- •6.1 Введение и краткий обзор
- •6.2.3 Иерархия классов
- •6.2.4 Поля типа
- •6.4.1 Монитор экрана
- •6.5 Множественное наследование
- •7.1 Введение
- •7.3 Пользовательские операции преобразования типа
- •7.3.2 Операции преобразования
- •7.3.3 Неоднозначности
- •7.5 Большие объекты
- •Void f2(t a) // вариант с контролем
- •Void f3(t a) // вариант с контролем
- •Inv() обращает саму матрицу m, а не возвращает новую, обратную m,
- •7.13 Предостережения
- •8.1 Введение
- •8.4.4 Неявная передача операций
- •8.4.5 Введение операций с помощью параметров шаблонного класса
- •8.7.1 Задание реализации с помощью параметров шаблона
- •9.1 Обработка ошибок
- •9.1.2 Другие точки зрения на особые ситуации
- •9.3.2 Производные особые ситуации
- •9.4.2 Предостережения
- •9.4.3 Исчерпание ресурса
- •9.4.4 Особые ситуации и конструкторы
- •9.5 Особые ситуации могут не быть ошибками
- •10.1 Введение
- •10.2 Вывод
- •10.2.1 Вывод встроенных типов
- •10.4.1.2 Поля вывода
- •10.4.1.4 Вывод целых
- •Istream - шаблон типа smanip, а smanip - двойник для ioss.
- •10.5.1 Закрытие потоков
- •10.5.2 Строковые потоки
- •X Целый параметр выдается в шестнадцатеричной записи;
- •11.1 Введение
- •11.2 Цели и средства
- •11.3 Процесс развития
- •11.3.1 Цикл развития
- •11.3.2 Цели проектирования
- •11.3.3 Шаги проектирования
- •11.3.3.1 Шаг 1: определение классов
- •11.3.3.2 Шаг 2: определение набора операций
- •11.3.3.3 Шаг 3: указание зависимостей
- •11.3.3.4 Шаг 4: определение интерфейсов
- •11.3.3.5 Перестройка иерархии классов
- •11.3.3.6 Использование моделей
- •11.3.4 Эксперимент и анализ
- •11.3.5 Тестирование
- •11.3.6 Сопровождение
- •11.3.7 Эффективность
- •11.4 Управление проектом
- •11.4.1 Повторное использование
- •11.4.2 Размер
- •11.4.3 Человеческий фактор
- •11.5 Свод правил
- •11.6 Список литературы с комментариями
- •12.1 Проектирование и язык программирования.
- •12.1.1 Игнорирование классов
- •12.1.2 Игнорирование наследования
- •12.1.3 Игнорирование статического контроля типов
- •12.1.4 Гибридный проект
- •12.2 Классы
- •12.2.1 Что представляют классы?
- •12.2.2 Иерархии классов
- •12.2.3 Зависимости в рамках иерархии классов.
- •Vertical_scrollbar или с помощью одного типа scrollbar, который
- •12.2.6 Отношения использования
- •12.2.7 Отношения внутри класса
- •12.3 Компоненты
- •12.4 Интерфейсы и реализации
- •12.5 Свод правил
- •13.1 Введение
- •13.2 Конкретные типы
- •13.4 Узловые классы
- •1, 2, 6 И 7. Класс, который не удовлетворяет условию 6, походит
- •13.5.1 Информация о типе
- •13.6 Обширный интерфейс
- •13.7 Каркас области приложения
- •13.8 Интерфейсные классы
- •13.10 Управление памятью
3.2.5 Преобразование типа
Иногда бывает необходимо явно преобразовать значение одного типа в
значение другого. Результатом явного преобразования будет
значение указанного типа, полученное из значения другого типа.
Например:
float r = float(1);
Здесь перед присваиванием целое значение 1 преобразуется в значение
с плавающей точкой 1.0f. Результат преобразования типа не является
адресом, поэтому ему присваивать нельзя (если только тип не является
ссылкой).
Существуют два вида записи явного преобразования типа:
традиционная запись, как операция приведения в С, например, (double)a
и функциональная запись, например, double(a). Функциональную запись
нельзя использовать для типов, которые не имеют простого имени.
Например, чтобы преобразовать значение в тип указателя, надо или
использовать приведение
char* p = (char*)0777;
или определить новое имя типа:
typedef char* Pchar;
char* p = Pchar(0777);
По мнению автора, функциональная запись в нетривиальных случаях
предпочтительнее. Рассмотрим два эквивалентных примера:
Pname n2 = Pbase(n1->tp)->b_name; // функциональная запись
Pname n3 = ((Pbase)n2->tp)->b_name; // запись с приведением
Поскольку операция -> имеет больший приоритет, чем операция приведения,
последнее выражение выполняется так:
((Pbase)(n2->tp))->b_name
Используя явное преобразование в тип указателя можно выдать данный объект
за объект произвольного типа. Например, присваивание
any_type* p = (any_type*)&some_object;
позволит обращаться к некоторому объекту (some_object) через указатель
p как к объекту произвольного типа (any_type). Тем не менее, если
some_object в действительности имеет тип не any_type, могут получиться
странные и нежелательные результаты.
Если преобразование типа не является необходимым, его вообще следует
избегать. Программы, в которых есть такие преобразования, обычно
труднее понимать, чем программы, их не имеющие. В то же время
программы с явно заданными преобразованиями типа понятнее,
чем программы, которые обходятся без таких преобразований, потому что
не вводят типов для представления понятий более высокого уровня.
Так, например, поступают программы, управляющие регистром устройства с
помощью сдвига и маскирования целых, вместо того, чтобы определить
подходящую структуру (struct) и работать непосредственно с ней
(см. $$2.6.1). Корректность явного преобразования типа часто
существенно зависит от того, насколько программист понимает, как язык
работает с объектами различных типов, и какова специфика данной реализации
языка. Приведем пример:
int i = 1;
char* pc = "asdf";
int* pi = &i;
i = (int)pc;
pc = (char*)i; // осторожно: значение pc может измениться.
// На некоторых машинах sizeof(int)
// меньше, чем sizeof(char*)
pi = (int*)pc;
pc = (char*)pi; // осторожно: pc может измениться
// На некоторых машинах char* имеет не такое
// представление, как int*
Для многих машин эти присваивания ничем не грозят, но для некоторых
результат может быть плачевным. В лучшем случае подобная программа
будет переносимой. Обычно без особого риска можно предположить,
что указатели на различные структуры имеют одинаковое представление.
Далее, произвольный указатель можно присвоить (без явного преобразования
типа) указателю типа void*, а void* может быть явно преобразован
обратно в указатель произвольного типа.
В языке С++ явные преобразования типа оказывается излишними во многих
случаях, когда в С (и других языках) они требуются. Во многих
программах можно вообще обойтись без явных преобразований типа, а во
многих других они могут быть локализованы в нескольких подпрограммах.