LEC_cpp6 (1119521)
Текст из файла
7 лекция - C++ (6).
Множественное наследование.
Новый (производный) класс может быть создан на основе произвольного числа базовых классов.
Пример:
class A { ... };
class B { ... };
class C : public A, protected B { ... };
!!! Спецификатор доступа распространяется только на один базовый класс; для других начинает действовать принцип умолчания.
!!! Объединение (union) не может иметь базовых классов и само не может быть базой.
!!! Класс не может появляться как непосредственно базовый дважды:
class C : public A, public A { ... }; - Er.!
н о может быть более одного раза непрямым базовым классом:
class L { public: int n; ... };
class A : public L { ... };
class B : public L { ... };
class C : public A, public B { ... void f (); ... };
Здесь решетка смежности такая: L <-- A <-- C --> B --> L .
При этом может возникнуть неоднозначность из-за «многократного» базового класса.
-
О доступе к членам производного класса:
void C::f () { ... n = 5; ...} // Er.! – неясно, чье n, но
void С::f () { ...A::n = 5; ...} O.K.! , либо B::n = 5;
Имя класса в операции разрешения видимости (А или В) – это указание, в каком классе в решетке смежности искать заданное имя.
-
О преобразовании указателей:
Ранее было сказано, что указатель на объект производного класса может быть неявно преобразован к указателю на объект базового класса. Для выписанных ранее примеров это было верно.
!!! Но этот базовый класс должен быть однозначным и доступным !!!
Продолжение предыдущего примера:
void g () {
C* pc = new C;
L* pl = pc; // Er.! – L не является однозначным,
pl = (L*) pc; // Er.! – явное преобразование не помогает,
// но возможно:
pl = (L*)(А*) pc; // либо pl = (L*)(В*) pc; O.K.! – сначала к A, затем к L из А.
Базовый класс считается доступным в некоторой области видимости, если доступны его public-члены.
class B { public: int a; ... };
class D : private B { ... };
void g () {
D* pd = new D;
B* pb = pd; // Er.! – в g() public-члены В, унаследованные D, недоступны,
// такое преобразование может осуществлять только
// функция-член D, либо друзья D.
}
-
Виртуальные базовые классы.
Изменим предыдущий пример так, чтобы класс L в классе С был в одном экземпляре:
class L { public: int n; ... };
class A : virtual public L { ... };
class B : virtual public L { ... };
c
L
A B
CC
lass C : public A, public B { ... void f (); ... };
Теперь решетка смежности будет такой:
и теперь допустимо:
void C :: f () { ... n = 5; ...} // О.К.! – n в одном экземпляре
void g () {
С* pс = new С;
L* pl = pc; // O.K.! – появилась однозначность.
}
-
Неоднозначность из-за совпадающих имен в различных базовых классах.
class A { class B {
public: int a;
int a; void b ();
void (*b) (); void h (char); void f (); public:
void g (); ... void f ();
}; int g;
void h ();
void h (int); ...
};
class C : public A, public B { ... };
Правила выбора имен в производном классе:
1 шаг: контроль однозначности (т.е. анализируемое имя определено в одном
базовом классе или в нескольких); при этом контекст не привлекается,
совместное использование (в одном из базовых классов) допускается.
2 шаг: если однозначно определенное имя есть имя перегруженной функции,
то пытаются разрешить анализируемый вызов (т.е. найти best-maching).
3 шаг: если предыдущие шаги завершились успешно, то проводится контроль
доступа.
void gg (C* pc) {
pc --> a = 1; // Er.! – A::a или B::b
pc --> b(); // Er.! – нет однозначности
pc --> f (); // Er.! – нет однозначности
pc --> g (); // Er.! – нет однозначности, контекст не привлекается!
pc --> g = 1; // Er.! – нет однозначности, контекст не привлекается!
pc --> h (); // O.K.!
pc --> h (1); // O.K.!
pc --> h (‘a’); // Er.! – доступ в последнюю очередь
pc --> A::a = 1; // O.K.! – т.е. снимаем неоднозначность с помощью
оператора разрешения области видимости.
}
Константные методы.
Иногда программист хочет быть уверенным, что используемый им метод класса не будет модифицировать передаваемый по ссылке фактический параметр. Для этого перед соответствующим формальным параметром можно использовать квалификатор const. Тогда компилятор C++ проверит допустимость всех операций, производимых с этим параметром, чтобы исключить модификацию состояния параметра.
Но как быть с вызовами других методов класса для передаваемого константного объекта, если о них не известно, изменяют они объект или нет.
Для решения этой проблемы Б. Страуструп расширил синтаксис С++, разрешив явно информировать, что данный метод не изменяет состояние объекта (сразу после заголовка указывается квалификатор const). Вследствие этого стало возможным определять константные методы и вызывать их для константных объектов (вызов неконстантного метода для константного объекта приводит к ошибке).
Расширим наш класс string следующими методами:
class string {
//...
public:
//...
string & concat ( const string & s ) // конкатенация с другой строкой
int length () const {return size;} // возвращает длину строки
};
Объявив метод length константным, мы явно разрешаем его вызов для константных объектов типа string. Поэтому реализация метода concat, использующего функцию length с константным формальным параметром, станет допустимой.
Замечания:
-
Следует различать константные параметры, передаваемые по значению, когда запрещается менять формальный параметр в теле функции, например,
void f (const int i, const myclass ob) {
i = 1; // Er!
ob.f (); // Er!, если f() неконстантный метод
}
и константные параметры, передаваемые по ссылке (адресу), когда запрещается менять соответствующий фактический параметр в теле функции. В случае параметра – указателя сам передаваемый адрес менять можно, например,
void f (const int * i, const myclass & ob) {
i = NULL; // O.K.!
*i = 3; // Er!
ob.f(); // Er!, если f() неконстантный метод
}
-
Следует учитывать, что поскольку программисту доступны операции над указателями, то обойти статическую систему защиты константных объектов не составляет труда, но такой стиль является признаком дурного тона и чреват появлением ошибок.
Статические члены класса.
По аналогии с понятием статического объекта в классе допускается объявлять статические члены-данные и члены-функции (с квалификатором static).
Статические члены-данные существуют в одном экземпляре и доступны для всех объектов данного класса. Можно считать, что статический член класса аналогичен глобальному объекту с ограничением видимости (для доступа нужна квалификация). Статические члены-данные класса существуют независимо от конкретных экземпляров класса, поэтому к статическому члену класса можно обращаться еще до размещения в памяти первого объекта этого класса. Но, программист должен предусмотреть выделение памяти (в соответствующем модуле) под каждый статический член класса, т.к. при объявлении самого класса или его экземпляров сама по себе память под статические члены не выделяется.
Доступ к статическому полю можно осуществлять через имя класса (без указания имени соответствующего экземпляра) и оператор разрешения области видимости «:: »:
class A {
public:
static int x;
static void f (char c);
};
int A::x; // !!! – размещение статического объекта в памяти
A::x = 10;
Вызов статических методов также можно производить «напрямую» через имя класса: A::f ('a');
Одно из очевидных применений статических методов — манипуляция глобальными объектами или статическими полями данных соответствующего класса (без необходимости выделения памяти под его экземпляр).
Статические функции не могут:
- пользоваться нестатическими членами-данными класса,
- пользоваться указателем this , т.е. использовать объект, от имени которого происходи обращение к функции,
- быть виртуальными и константными (inline - могут).
Инициализация статических полей данных.
/*Допускается инициализировать внутри определения класса статические поля данных только базовых типов (int, char и bool).*/ Статические поля других типов (и нестатические поля любых типов) должны определяться (инициализироваться) за пределами описания класса.
5
Характеристики
Тип файла документ
Документы такого типа открываются такими программами, как Microsoft Office Word на компьютерах Windows, Apple Pages на компьютерах Mac, Open Office - бесплатная альтернатива на различных платформах, в том числе Linux. Наиболее простым и современным решением будут Google документы, так как открываются онлайн без скачивания прямо в браузере на любой платформе. Существуют российские качественные аналоги, например от Яндекса.
Будьте внимательны на мобильных устройствах, так как там используются упрощённый функционал даже в официальном приложении от Microsoft, поэтому для просмотра скачивайте PDF-версию. А если нужно редактировать файл, то используйте оригинальный файл.
Файлы такого типа обычно разбиты на страницы, а текст может быть форматированным (жирный, курсив, выбор шрифта, таблицы и т.п.), а также в него можно добавлять изображения. Формат идеально подходит для рефератов, докладов и РПЗ курсовых проектов, которые необходимо распечатать. Кстати перед печатью также сохраняйте файл в PDF, так как принтер может начудить со шрифтами.