Если через объект класса C попытаться обратиться к методам класса W, то компилятор выдаст ошибку. Выходом из этой проблемы будет использование виртуального базового класса
//f1.h
#include <iostream.h>
class W
{public:
virtual void f() {cout<<"W::f()"<<endl;}
virtual void g() {cout<<"W::g()"<<endl;}
virtual void h() {cout<<"W::h()"<<endl;}
};
class A:public virtual W
{public:
void g() {cout<<"A::g()"<<endl;}
};
class B:public virtual W
{public:
void f() {cout<<"B::F()"<<endl;}
};
class C: public A, public B
{public:
void f() {cout<<"C::f()"<<endl;}
};
//f1.cpp
#include "f1.h"
void main()
{ C* pc = new C;
pc->f(); //C::f()
pc->g(); //A::g()
pc->h(); //W::h()
((A*)pc)->f(); //C::f(). pc – указатель на C, насильственно преобразуем его к указателю на A; в описании класса A функции f нет, она описана в базовом классе W, но как виртуальная; далее происходит анализ класса, на который указывает pc, то есть класса C, в нем обнаруживается реализация функции f(), вызов которой и происходит. Если слово virtual перед f() в W убрать, тогда будет вызвана f из W.
((W*)pc)->f(); //C::f()
B* pb = new B;
pb->f(); //B::f()
pb->g(); //W::g();
pb->h(); //W::h()
((W*) pb)->f(); //B:f()
A* pa = new A;
pa->f(); //W::f()
pa->g(); //A::g()
pa->h(); //W::h()
((W*) pa)->g(); //A::g()
}
Для описания иерархий множественного наследования используется прямой ациклический граф. Виртуальные базовые классы инициализируются перед любыми невиртуальными базовыми классами в том порядке, в котором они появляются в прямом ациклическом графе наследования при просмотре его снизу вверх и слева направо. Для приведенного выше примера порядок вызова конструкторов следующий: W(), A(), B(), C().
class A {};
class B: public virtual A {};
class C: public virtual A {};
class D: public A {};
class E: public B, public C, public D {};
Дерево наследования приведенной выше иерархии изображено на рисунке ниже.
Порядок вызова конструкторов для класса E таков: A(), B(), C(), D(), E().
Ключ доступа
Спецификатор базового доступа
Доступ в производном классе
Комментарий
private
private
protected
public
private
private
private
все private
protected
private
protected
public
private
protected
protected
все protected, кроме private
public
private
protected
public
private
protected
public
не изменяется
Задачи
Во всех заданиях реализовать вывод на экран, методы получения значений полей и методы установки значений полей, а также необходимые конструкторы.
1. Товарный чек содержит список товаров, купленных покупателем в магазине. Один элемент списка представляет собой пару: товара – сумма. Товар – это класс Goods с полями кода и наименования товара, цены за единицу товара, количества покупаемых единиц товара. В классе должны быть реализованы методы доступа к полям для получения и изменения информации, а также метод вычисления суммы оплаты за товар. Для моделирования товарного чека реализовать класс Receipt, полями которого являются номер товарного чека, дата и время его создания, список покупаемых товаров. В классе Receipt реализовать методы добавления, изменения и удаления записи о покупаемом товаре, а также метод подсчета общей суммы. Перегрузить операторы ввода/вывода объектов.
2. Создать базовый класс Car, характеризуемый торговой маркой (строка), числом цилиндров, мощностью. Определить методы чтения и изменения мощности. Создать производный класс Lorry (грузовик), характеризуемый дополнительно грузоподъемностью кузова. Определить функции переназначения марки и изменения грузоподъемности.
3. Создать класс Liquid (жидкость), имеющий поля названия и плотности. Определить методы переназначения и изменения плотности. Создать производный класс Alcohol (спирт), имеющий крепость. Определить методы переназначения и изменения крепости
4. Создать класс валюта для работы с денежными суммами. Определить виртуальные функции перевода в рубли и вывода на экран. Реализовать производные классы Dollar и Euro со своими функциями перевода и вывода на экран
5. Создать иерархию классов, позволяющую описать как отдельные составляющие компьютера, так и компьютер в целом. В качестве классов использовать материнскую плату, процессор, видеокарту, компьютер. Реализовать в виде наследования и контейнерных классов
6. Создать базовый класс «матрица1», описав в нем функции ввода матрицы с клавиатуры, вывода ее на экран и нахождения суммы элементов матрицы. Породить от него класс «матрица2», переопределив в нем функцию ввода матрицы таким образом, чтобы значения элементов матрицы загружались из файла.
7. Создать базовый класс «массив1», описав в нём функции добавления, удаления, вывода на экран и подсчета количества ненулевых элементов массива. Породить от него класс «массив2», переопределив функцию удаления элемента массива таким образом, чтобы, если удаляемый элемент равен нулю, то обнулялись соседние с ним элементы.