
- •5.Препроцессор. Директивы препроцессора.
- •7.Работа с файлами. Текстовый и двоичный режим.
- •8.Указатели. Адресная арифметика.
- •10.Перечислимый тип. Структуры. Объединения.
- •11.Поразрядные операции.
- •13.Спецификаторы класса памяти.
- •14.Пространства имён.
- •15.Компоновка. Правило одного определения.
- •16.Понятие класса.
- •17.Функции-члены класса. Указатель this.
- •18.Конструкторы. Деструкторы.
- •19.Преобразования объектов класса.
- •20.Доступ к членам класса.
- •21.Статические члены класса.
- •22.Друзья класса.
- •23.Совместное использование.
- •24.Перегрузка операций.
- •25.Шаблоны.
- •26.Обработка исключительных ситуаций.
- •27.Производные классы.
- •28.Виртуальные функции. Абстрактные классы.
- •29.Указатели на члены класса.
- •30.Множественное наследование.
- •31.Структура dll-библиотеки.
- •32.Статическое и динамическое подключение dll-библиотек.
- •34.Регистры процессора.
- •35.Использование стека. Команды работы со стеком в языке ассемблера.
- •36.Арифметические команды в языке ассемблера.
- •37.Команды сравнения и перехода в языке ассемблера.
- •38.Команды работы с битами в языке ассемблера.
- •39.Процедуры в языке ассемблера. Передача параметров в процедуру.
- •40.Процедуры в языке ассемблера. Возврат результата. Локальные данные.
30.Множественное наследование.
Класс может быть порождён из любого числа базовых классов. Наличие более чем одногонепосредственного базового класса называется множественным наследованием. class A { ... }; class B { ... }; class C { ... }; class D : public A, public B, private C { ... }; Указатель на производный класс можно передать в функции, которые ожидают указатель на один из базовых классов. Реализация этого механизма подразумевает простые методы компиляции для обеспечения того, что функция, ожидающая указатель на один базовый класс, увидит часть производного класса, отличную от той, которую увидит функция, ожидающая указатель на другой базовый класс. Виртуальные функцииработают как обычно. class A
{ public:
void f1();
virtual void g() = 0; };
class B
{ public:
void f2();
virtual void h() = 0; };
class C : public A, public B
{ public:
void g(); // Замещение A::g()
void h(); // Замещение B::h()
};
void f1(A *p) { p->f1(); }
void f2(B *p) { p->f2(); }
void main()
{ C c;
f1(&c);
f2(&c);
A *p = &c;
p->g(); // Правильно
p->h(); // Ошибка: функция h не является членом класса А
dynamic_cast<B *>(p)->h(); // Правильно
}
Класс не может быть задан в качестве непосредственного базового класса более одного раза, но он может быть более одного раза косвенным базовым классом.
class A { ... }; class B : public A, public A { ... }; |
// Ошибка! |
class A { ... }; class B : public A { ... }; class C : public A { ... }; class D : public B, public C { ... }; |
// Всё правильно |
Здесь объект класса D будет иметь два подобъекта класса A.
Производный класс и его базовые классы могут быть представлены в виде направленного ациклического графа.
Класс не может появляться дважды в списке базовых классов просто потому, что каждая ссылка на него или его члены была бы неоднозначной. Эта проблема не возникает, если класс появляется дважды в качестве косвенного базового класса. Объект класса D имеет два подобъекта класса A – B::A и C::A.
Поскольку в объекте D имеется два объекта A, приведение (явно или неявное) между указателем на A и указателем на D неоднозначно и поэтому запрещено.
D *pd = new D;
A *pa = pd; pa = (A *)pd; pa = (B *)pd; pa = (С *)pd; |
// Неоднозначность! // Всё равно неоднозначность! // Приведение к указателю на A в объекте B // Приведение к указателю на A в объекте С |
Однако класс может быть одновременно непосредственным и косвенным базовым классом.
class A { ... };
class B : public A { ... };
class C : public A { ... };
class D : public A, public B, public C { ... };
pa = pd; pa = (B *)pd; pa = (С *)pd; |
// Можно!
// Приведение к указателю на A непосредственно в объекте D // Приведение к указателю на A в объекте B // Приведение к указателю на A в объекте С |