- •Часть 1:
- •Имена, их области существования и видимости.
- •Объявления и определения.
- •Атрибуты компоновки имен.
- •Использование имен на различных стадиях создания программ.(спросить)
- •Объекты, их типы и классы памяти.
- •Имена типов данных. (спросить)
- •Встроенные и составные типы данных. Квалификатор const.
- •Рекурсивный вызов функций. Тип «указатель на функцию» (спросить). 82
- •Перегрузка функций.
- •Шаблоны функций.
- •Часть 2:
- •Процедурное и объектно-ориентированное программирование.
- •Понятие класса.
- •Работа с this.
- •Конструкторы и деструкторы, их вызов.
- •Уровни доступа. Использование дружественных классов.
- •Перегрузка операций.
- •Абстрактные базовые классы.
- •Шаблоны классов.
- •Часть 3:
- •Множественное наследование.
- •Явные преобразования static_cast, dynamic_cast.
- •Обработка исключительных ситуаций.
Часть 3:
Множественное наследование.
Множественное наследование означает, что класс имеет несколько базовых классов. Если в базовых классах есть одноименные элементы, при этом может произойти конфликт идентификаторов, который устраняется с помощью операции доступа к области видимости:
class monstr{
public: int get_health();
class hero{
public: int get_health();
}:
class ostrich: public monstr, public hero{ }:
int main(){ ostrich A;
cout « A.monstr::get_health(); cout « A.hero::get_health();
}
Как видно из примера, для вызова метода gethealth требуется явно указывать класс, в котором он описан. Использование обычной для вызова метода класса конструкции A.gethealthO приведет к ошибке, поскольку компилятор не в состоянии разобраться, к методу какого из базовых классов требуется обратиться.
Если у базовых классов есть общий предок, это приведет к тому, что производный от этих базовых класс унаследует два экземпляра полей предка, что чаще всего является нежелательным. Чтобы избежать такой ситуации, требуется при наследовании общего предка определить его как виртуальный класс:
class monstr{ }:
class daemon: virtual public monstr{ }:
class lady: virtual public monstr{
class baby: public daemon, public lady{ }:
Класс baby содержит только один экземпляр полей класса monstr. Если базовый класс наследуется и как виртуальный, и обычным образом, в производном классе будут присутствовать отдельные экземпляры для каждого невиртуального вхождения и еще один экземпляр для виртуального.
Множественное наследование применяется для того, чтобы обеспечить производный класс свойствами двух или более базовых. Чаще всего один из этих классов является основным, а другие обеспечивают некоторые дополнительные свойства, поэтому они называются классами подмешивания. По возможности классы подмешивания должны быть виртуальными и создаваться с помощью конструкторов без параметров, что позволяет избежать многих проблем, возникающих при ромбовидном наследовании (когда у базовых классов есть общий предок).
Идентификация типа во время выполнения.
Средства преобразования типов.
Явные преобразования static_cast, dynamic_cast.
Операция static_cast
Операция static_cast используется для преобразования типа на этапе компиляции между:
целыми типами;
целыми и вещественными типами;
целыми и перечисляемыми типами;
указателями и ссылками на объекты одной иерархии, при условии, что оно однозначно и не связано с понижающим преобразованием виртуального базового класса.
Формат операции:
Static_cast <тип> (выражение)
Результат операции имеет указанный тип, который может быть ссылкой, указателем, арифметическим или перечисляемым типом,
При выполнении операции внутреннее представление данных может быть модифицировано, хотя численное значение остается неизменным. Например:
float f - 100:
int ,i = static_cast <int> (f);
// Целые и вещественные имеют различное внутреннее представление
Такого рода преобразования применяются обычно для подавления сообщений компилятора о возможной потере данных в том случае, когда есть уверенность, что требуется выполнить именно это действие. Результат преобразования остается на совести программиста.
Операция static_cast позволяет выполнять преобразования из производного класса в базовый и наоборот без ограничений:
class В{};
class С: public В{}: С с:
В *bp = static_cast<B*>(c): // Производный -> базовый В b:
С &ср = static_cast<C&>(b); // Базовый -> производный
Преобразование выполняется при компиляции, при этом объекты могут не быть полиморфными. Программист должен сам отслеживать допустимость дальнейших действий с преобразованными величинами.
В общем случае использование для преобразования указателей родственных классов иерархии предпочтительнее использовать операцию dynamic_cast. В этом случае если преобразование возможно на этапе компиляции, генерируется тот же код, что и для static_cast. Кроме того, dynamic_cast допускает перекрестное преобразование, нисходящее приведение виртуального базового класса и производит проверку допустимости приведения во время выполнения.
Операция dynamic_cast
Операция применяется для преобразования указателей родственных классов иерархии, в основном — указателя базового класса в указатель на производныйкласс, при этом во время выполнения программы производится проверка допустимости преобразования.
Формат операции:
dynamiccast <тип *> (выражение)
Выражение должно быть указателем или ссылкой на класс, тип — базовым или производным для этого класса. После проверки допустимости преобразования в случае успешного выполнения операция формирует результат заданного типа, в противном случае для указателя результат равен нулю, а для ссылки порождается исключение bad_cast. Если заданный тип и тип выражения не относятся к одной иерархии, преобразование не допускается.
Повышающее преобразование
Выполнение с помощью операции dynamic_cast повышающего преобразования равносильно простому присваиванию:
class В{ /* ... */ }:
class C: public В{ /* ... */ }:
C* с = new C:
В* b = dynamic_cast<B*>(c); // Эквивалентно В* b = с:
Понижающее преобразование
Чаще всего операция dynamic_cast применяется при понижающем преобразовании — когда компилятор не имеет возможности проверить правильность приведения.
Производные классы могут содержать функции, которых нет в базовых классах. Для их вызова через указатель базового класса нужно иметь уверенность, что этот указатель в действительности ссылается на объект производного класса. Такая проверка производится в момент выполнения приведения типа с использованием RTTI (run-time type information) — «информации о типе во время выполнения программы». Для того чтобы проверка допустимости могла быть выполнена, аргумент операции dynamic_cast должен быть полиморфного типа, то есть иметь хотя бы один виртуальный метод (см. с. 205).
Для использования RTTI необходимо подключить к программе заголовочный файл <typeinfo>. Кроме того, необходимо, чтобы был установлен соответствующий режим компилятора.
С помощью операции dynamic_cast такое преобразование возможно при условии, что класс является полиморфным и преобразование недвусмысленно. Рассмотрим пример, в котором выполняется понижающее преобразование виртуального базового класса:
#include <iostream.h>
#include <typeinfo.h>
class A{
public: virtual ~A(){};};
class B: public virtual A{}:
class С: public virtual A{};
class D: public B. public C{};
void demo(A *a){
D* d - dynamic_cast<D*>(a);
if (d) { ... }
}
int main(){
D *d - new D; demo(d); return 0:
}
Преобразование ссылок
Для аргумента-ссылки смысл операции преобразования несколько иной, чем для указателя. Поскольку ссылка всегда указывает на конкретный объект, операция dynaramic_cast должна выполнять преобразование именно к типу этого объекта. Корректность приведения проверяется автоматически, в случае несовпадения порождается исключение badcast:
Перекрестное преобразование
Операция dynamic_cast позволяет выполнять безопасное преобразование типа между производными классами одного базового класса.