- •Доступ к наследуемым членам.
- •Статусы доступа при наследовании классов
- •Начальная часть таблицы, выводимой по этой программе, имеет вид:
- •Полиморфизм. Механизм виртуальных функций. Привести примеры.
- •34. Абстрактный класс. Чисто виртуальные функции
- •36. Шаблоны классов. Форматы описания шаблона класса, методов и объектов шаблонного класса.
- •Жизненный цикл программы.
34. Абстрактный класс. Чисто виртуальные функции
Чисто виртуальная функция (pure virtual function) является функцией, которая объявляется в базовом классе, но не имеет в нем определения. Поскольку она не имеет определения, то есть тела в этом базовом классе, то всякий производный класс обязан иметь свою собственную версию определения. Для объявления чисто виртуальной функции используется следующая общая форма: virtual тип имя_функции(список параметров) = 0;
Здесь тип обозначает тип возвращаемого значения, а имя_функции является именем функции. Например, следующая версия функции show_area() класса figure является чисто виртуальной функцией. class figure { double х, у; public: void set_dim(double i, double j=0) { x = i; y = j; } virtual void show_area() = 0; // чисто виртуальная };
При введении чисто виртуальной функции в производном классе обязательно необходимо определить свою собственную реализацию этой функции. Если класс не будет содержать определения этой функции, то компилятор выдаст ошибку. Например, если попытаться откомпилировать следующую модифицированную версию программы figure, в которой удалено определение функции snow_area() из класса circle, то будет выдано сообщение об ошибке: /* Данная программа не компилируется, поскольку класс circle не переопределил show_агеа() */ #include <iostream.h> class figure { protected: double x, y; public: void set_dim(double i, double j) { x = i; у = j; } virtual void show_area() = 0; // pure }; class triangle: public figure { public: void show_area() { cout << "Triangle with height "; cout << x << " and base " << y; cout << " has an area of "; cout << x * 0.5 * у << ". \ n"; } }; class square: public figure { public: void show_area() { cout << "Square with dimensions "; cout << x << "x" << y; cout << " has an area of "; cout << x * у << " . \n"; } }; class circle: public figure { // определение show_area() отсутствует и потому выдается ошибка }; int main ( ) { figure *р; // создание указателя базового типа circle с; // попытка создания объекта типа circle - ОШИБКА triangle t; // создание объектов порожденных типов square s; p = &t; p->set_dim(10.0, 5.0); p->show_area (); p = &s; p->set_dim(10.0, 5.0); p->show_area(); return 0; }
Если какой-либо класс имеет хотя бы одну виртуальную функцию, то такой класс называется абстрактным (abstract). Важной особенностью абстрактных классов является то, что не существует ни одного объекта данного класса. Вместо этого абстрактный класс служит в качестве базового для других производных классов. Причина, по которой абстрактный класс не может быть использован для объявления объекта, заключается в том, что одна или несколько его функций-членов не имеют определения. Тем не менее, даже если базовый класс является абстрактным, все равно можно объявлять указатели или ссылки на него, с помощью которых затем поддерживается полиморфизм времени исполнения.
35.Множественное наследование в С++. Прямая и косвенная база. Исключение дублирования членов в производных классах..
Как уже отмечалось, в С++ производный класс может быть порождён из любого числа непосредственных базовых классов. Наличие у производного класса более чем одного непосредственного базового класса называется множественным наследием. Синтаксически множественное наследование отличается от единичного наследования списком порождения, состоящим более чем из одного класса.
//Листинг 7. Пример множественного наследования
class A
{int a1;
public:
int a2;
void funcA()
};
class B
{int b1;
public:
int b2;
void funcB()
};
class C: public A, public B //наследуем класс С от A и B
{int c1;
public:
int c2;
void funcC()
};
Схема иерархии классов, определенных в последнем примере, изображена на рис.4
При множественном наследовании один и тот же класс не может быть дважды указан как прямой базовый, однако, косвенным базовым классом один и тот же класс может быть и более одного раза.
class A {public: int x; void funcA(); …};
class B: public A {…};
class D: public A{…};
class C: public B, public D {…};
Дублирование косвенного базового класса (рис 5а) приводит к включению в производный класс нескольких объектов базового класса. Для класса С в последнем примере это означает, что компонентное данное x будет существовать в объектах данного класса в двух экземплярах – один унаследован через класс В, другой – через класс D, что порождает проблему неоднозначности при доступе к дублирующимся компонентам класса: неясно, какой из одноименных компонент изменится при следующем обращении
main()
{ C c;
c.x=6; // Ошибка!!!
}
Попытка доступа к члену данных x для объекта с приводит к ошибке транслятора “Member is ambiguous A::x and A::x”. Эта ошибка означает, что транслятор не может определить, какому из двух компонент x класса необходимо присвоить новое значение. Неразрешимыми именами для транслятора будут также следующие с.C::x и c.A::x. Решением проблемы является использование квалифицированных имен компонент с использованием имен классов Bи D. Для транслятора однозначно различаются следующие имена компонент: с.B::x (компонента, унаследованная через класс В) и c.D::x (компонента, унаследованная через класс D). Именно из-за сложности управления одноименными унаследованными компонентами класса множественное наследование реализаций было запрещено в языках программирования, появившихся после С++ ( например, в C# и Java).
Еще один вариант множественного наследования классов в языке С++ - использование виртуальных базовых классов. Если компоненты косвенного базового класса не должны дублироваться в классе-потомке, то он объявляется виртуальным:
class D {…};
class A: public virtual D {…};
class B: public virtual D {…};
class C: public A, public B{…};
Диаграмма классов в этом случае будет выглядеть как на рис. 5б. Компоненты косвенного базового класса присутствуют в классе С в единственном экземпляре, проблемы неоднозначности доступа к ним не возникает.
