Ключевая концепция. Соблюдение интерфейса базового класса

Важно понимать, что каждый класс определяет собственный интерфейс. Для взаимодействия с объектом типа класса следует использовать интерфейс этого класса, даже если он — часть базового класса в объекте производного.

В результате конструкторы производного класса не могут непосредственно инициализировать члены своего базового класса. Тело конструктора производного класса может присваивать значения его открытых или защищенных членов базового класса. Хотя он может присвоить значения этим членам, обычно это не применяется. Как и любой другой пользователь базового класса, производный класс должен соблюдать интерфейс своего базового класса, используя для инициализации своих унаследованных членов его конструктор.

Наследование и статические члены

Если в базовом классе определен статический (static) член (см. раздел 7.6), для всей иерархии существует только один его экземпляр. Независимо от количества классов, производных от базового класса, существовать будет только один экземпляр каждого статического члена.

class Base {

public:

 static void statmem();

};

class Derived : public Base {

 void f(const Derived&);

};

Статические члены подчиняются обычным правилам управления доступом: если член класса объявлен в базовом классе закрытым, производные классы не получат к нему доступа. Когда статический член класса доступен, к нему можно обращаться как из базового, так и из производного класса:

void Derived::f(const Derived &derived_obj) {

 Base::statmem();    // ok: statmem() определена в Base

 Derived::statmem(); // ok: Derived наследует statmem()

 // ok: объект производного класса применим для доступа к

 // статическому члену базового

 derived_obj.statmem(); // доступ в объекте класса Derived

 statmem();             // доступ в объекте этого класса

}

Объявления производных классов

Производный класс объявляется как любой другой класс (см. раздел 7.3.3). Объявление содержит имя класса, но не включает его список наследования:

class Bulk_quote : public Quote; // ошибка: здесь не может быть списка

                                 // наследования

class Bulk_quote;                // ok: правильный способ объявления

                                 // производного класса

Задача объявления в том, чтобы сообщить о существовании имени и какую сущность он обозначает: класс, функцию или переменную. Список наследования и все другие подробности определения должны присутствовать в теле класса.

Классы, используемые как базовые

Класс должен быть определен, а не только объявлен, прежде чем его можно будет использовать как базовый класс:

class Quote; // объявлен, но не определен

// ошибка: класс Quote следует определить

class Bulk_quote : public Quote { ... };

Причина этого ограничения очевидна: каждый производный класс содержит и может использовать члены, унаследованные от его базового класса. Чтобы использовать эти члены, производный класс должен знать, что они из себя представляют. Одним из следствий этого правила является невозможность наследования класса от себя самого.

Базовый класс сам может быть производным классом:

class Base { /* ... */ };

class D1: public Base { /* ... */ };

class D2: public D1 { /*...*/ };

В этой иерархии класс Base является прямым базовым (direct base class) для класса D1 и косвенным базовым (indirect base class) для класса D2. Прямой базовый класс указывают в списке наследования. Косвенный базовый класс наследуется производным через его прямой базовый класс.

Перейти на страницу:

Похожие книги