спецификация-базовых:
полное-имя-класса
virtual спецификация-доступа optполное-имя-класса
спецификация-доступа virtual optполное-имя-класса
спецификация-доступа:
private
protected
public
Конструкция имя-класса в спецификации-базовых должна обозначать ранее описанный класс (§R.9), который называется базовым по отношению к определяемому классу. Говорят, что класс является производным от своих базовых классов. Назначение конструкции спецификация-доступа объясняется в §R.11. К членам базового класса, если только они не переопределены в производном классе, можно обращаться так, как будто они являются членами производного класса. Говорят, что производный класс наследует члены базового класса. С помощью операции разрешения области видимости :: (§R.5.1) к члену базового класса можно обращаться явно. Такое обращение возможно и в том случае, когда имя члена базового класса переопределено в производном классе. Производный класс сам может выступать как базовый при контроле доступа, см. §R.11.2. Указатель на производный класс может неявно преобразовываться в указатель на однозначно определенный и доступный базовый класс (§R.4.6). Ссылка на производный класс может неявно преобразовываться в ссылку на однозначно определенный и доступный базовый класс (§R.4.7).
Рассмотрим пример:
class base {
public:
int a, b;
};
class derived: public base {
public:
int b, c;
};
void f()
{
derived d;
d.a = 1;
d.base::b = 2;
d.b = 3;
d.c = 4;
base* bp = &d; // стандартное преобразование derived* в base*
}
Здесь присваиваются значения четырем членам d, а bp настраивается на d.
Класс называется прямым базовым, если он находится в списке-базовых, и косвенным базовым, если сам не являясь прямым базовым, он служит базовым для одного из классов списка-базовых.
Отметим, что в обозначении имя-класса :: имя конструкция, имя может быть именем члена косвенного базового класса. Такое обозначение просто указывает класс, в котором следует начинать поиск этого имени.
Приведем пример:
class A { public: void f(); }
class B: public A {};
class C: public B { public: void f(); }
void C::f()
{
f(); // вызов f() из C
A::f(); // вызов f() из A
B::f(); // вызов f() из A
}
Здесь дважды вызывается A::f(), поскольку это единственная функция f() в классе B.
Инициализация объектов, представляющих базовые классы, задается в конструкторах, см. §R.12.6.2.
R.10.1 Множественные базовые классы
Класс может быть производным по отношению к любому числу базовых классов. Приведем пример:
class A {/*… */};
class B {/*… */};
class C {/*… */};
class D: public A, public B, public C {/*… */};
Использование более, чем одного прямого базового класса называется множественным наследованием.
Порядок наследования не важен, если не учитывать вопросов, связанных со стандартной инициализацией с помощью конструктора (§R.12.1), уничтожением (§R.12.4) и размещением в памяти ($$r.5.4, §R.9.2, §R.11.1). Порядок выделения памяти для базовых классов определяется реализацией.
Нельзя указывать класс в качестве прямого базового по отношению к производному классу более одного раза, но косвенным базовым классом он может быть неоднократно.
class B {/*… */};
class D: public B, public B {/*… */}; // недопустимо
class L {/*… */};
class A: public L {/*… */};
class B: public L {/*… */};
class C: public A, public B {/*… */}; // нормально
Здесь объект класса C будет иметь два вложенных объекта класса L.
К спецификации базового класса можно добавить служебное слово virtual. Отдельный объект виртуального базового класса V разделяется между всеми базовыми классами, которые указали V при задании своих базовых классов. Приведем пример:
class V {/*… */};
class A: virtual public V {/*… */};
class B: virtual public V {/*… */};
class C: public A, public B {/*… */};
Здесь объект класса C будет иметь только один вложенный объект класса V.
Класс может содержать виртуальные и невиртуальные базовые классы одного типа, например:
class B {/*… */};
class X: virtual public B {/*… */};
class Y: virtual public B {/*… */};
class Z: public B {/*… */};
class AA: public X, public Y, public Z {/*… */};
Здесь объект класса AA будет иметь два вложенных объекта класса B: из класса Z и виртуальный, разделяемый между классами X и Y.
Читать дальше