Материалы (12) (Материалы к лекциям)
Описание файла
Файл "Материалы (12)" внутри архива находится в папке "Материалы к лекциям". PDF-файл из архива "Материалы к лекциям", который расположен в категории "". Всё это находится в предмете "практика расчётов на пэвм" из 3 семестр, которые можно найти в файловом архиве МГУ им. Ломоносова. Не смотря на прямую связь этого архива с МГУ им. Ломоносова, его также можно найти и в других разделах. .
Просмотр PDF-файла онлайн
Текст из PDF
Множественное наследованиеclass A { ... };class B { ... };class C : public A, protected B { ... };Спецификатор доступа распространяется только на один базовый класс; длядругих базовых классов начинает действовать принцип умолчания.Класс не может появляться как непосредственно базовый дважды:class C : public A, public A { ... }; - ошибка!но может быть более одного раза непрямым базовым классом: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 .A::LСобственно АВ::LСобственно ВСобственно СПри этом может возникнуть неоднозначность из-за «многократного» базовогокласса.О доступе к членам производного классаvoid C::f () { ... n = 5; ...} // ошибка! – неясно, чье n, ноvoid С::f () { ...A::n = 5; ...} O.K.! , либо B::n = 5;Имя класса в операции разрешения видимости (А или В) –это указание, в каком классе в решетке смежности искатьзаданное имя.О преобразовании указателейУказатель на объект производного класса может быть неявнопреобразован к указателю на объект базового класса, толькоесли этот базовый класс является однозначным и доступнымПродолжение предыдущего примера:void g () {C* pc = new C;L* pl = pc;pl = (L*) pc;pl = (L*)(А*) pc;// ошибка! – L не является однозначным,// ошибка! – явное преобразование не помогает,// но возможно:// либо pl = (L*)(В*) pc; -- O.K.!Базовый класс считается доступным в некоторой области видимости, еслидоступны его public-члены.class B { public: int a; ...
};class D : private B { ... };void g () {D* pd = new D;B* pb = pd;}// ошибка! – в g() public-члены В, унаследованные// D, недоступны, такое преобразование// может осуществлять только// функция-член D, либо друзья D.Виртуальные базовые классыclass L { public: int n ; ... };class A : virtual public L { ... };class B : virtual public L { ... };class C : public A, public B { ... void f (); ... };Теперь решетка смежности будет такой:LАВСи теперь допустимо:void C :: f () { ... n = 5; ...} // О.К.! – n в одном экземпляреvoid g () {С* pс = new С;L* pl = pc;}// O.K.! – появилась однозначность.Неоднозначность из-за совпадающих имен в различныхбазовых классах.class A {public:int a;void (*b) ( );void f ( );void g ( ); ...};class B {int a;void b ( );void h (char);public:void f ( );int g;void h ( );void h (int); ...};class C : public A, public B { ...
}; //какие имена//неоднозначны ?Правила выбора имен в производном классе1 шаг:контроль однозначности (т.е. проверяется,определено ли анализируемое имя в одномбазовом классе или в нескольких); при этомконтекст не привлекается, совместноеиспользование (в одном из базовых классов)допускается.2 шаг:если однозначно определенное имя есть имяперегруженной функции, то пытаются разрешитьанализируемый вызов (т.е. найти best-maching).3 шаг:если предыдущие шаги завершились успешно, топроводится контроль доступа.Пример.class A {public: int a; void (*b) ( );void f ( ); void g ( ); ...};class B { int a; void b ( ); void h (char);public:void f ( ); int g; void h ( );void h (int); ...
};class C : public A, public B { ... };void gg (C* pc) {pc --> a = 1;// ошибка! – A::a или B::a для однозначностиpc --> b(); // ошибка! – нет однозначностиpc --> f (); // ошибка! – нет однозначностиpc --> g (); // ошибка! – нет однозначности,// контекст не привлекается!pc --> g = 1;// ошибка! – нет однозначности,// контекст не привлекается!pc --> h (); // O.K.!pc --> h (1);// O.K.!pc --> h (‘a’);// ошибка! – доступ в последнюю очередь, не доступноpc --> A::a = 1;// O.K.! – т.е.
снимаем неоднозначность// с помощью операции «::»pc --> B::a = 1;// ошибка! – поле a не доступно в B (private)}Механизм RTTI (Run-Time Type Identification).Механизм RTTI состоит из трех частей:1.операция dynamic_cast(в основном предназначена для получения указателя на объектпроизводного класса при наличии указателя на объект базовогокласса);2.операция typeid(служит для идентификации точного типа объекта при наличииуказателя на базовый класс);3.структура type_info( позволяет получить дополнительную информацию, ассоциированнуюс типом).Для использования RTTI в программу следует включить заголовок<typeinfo>.(1). Операция dynamic_cast реализует приведение типов (указателей или ссылок)полиморфных классов в динамическом режиме.(операции const_cast, reinterpret_cast и static_cast здесь не рассматриваются).Синтаксис использования операции dynamic_cast :dynamic_cast < целевой тип > ( выражение )Если даны два полиморфных класса B и D (причем D – производный от B), то dynamic_castвсегда может привести D* к B*.Также dynamic_cast может привести B* к D*, но только в том случае, если объект, на которыйуказывает указатель, действительно является объектом типа D (либо производным от него)!При неудачной попытке приведения типов результатом выполнения dynamic_cast является 0,если в операции использовались указатели.
Если же использовались ссылки, генерируетсяисключение типа bad_cast.Пример:Base *bp, b_ob;Derived *dp, d_ob;bp = &d_ob;dp = dynamic_cast <Derived *> (bp);if (dp)cout << «Приведение типов прошло успешно»;bp = &b_ob;dp = dynamic_cast <Derived *> (bp);if (!dp)cout << «Приведения типов не произошло»;(2)-(3) Информацию о типе объекта можно получить с помощью операции typeid.Синтаксис использования операции typeid:typeid (выражение)typeid (имя_типа)илиОперация typeid возвращает ссылку на объект класса type_info, представляющийлибо тип объекта, обозначенного заданным выражением, либо непосредственнозаданный тип.В классе type_info определены следующие открытые члены:bool operator == (const type_info & объект); // для сравнения типовbool operator != (const type_info & объект); // для сравнения типовbool before (const type_info & объект); // для внутреннего использованияconst char * name ( ); / /возвращает указатель на имя типаОператор typeid наиболее полезен, если в качестве аргумента задать указательполиморфного базового класса, т.к.
с его помощью во время выполнения программыможно определить тип реального объекта, на который он указывает. То же относитсяи к ссылкам.typeid может применяться к нулевым указателям (typeid (* р)). Если указатель наполиморфный класс р == 0, то будет сгенерировано исключение типа bad_typeid.Пример.class Base {virtual void f ( ) {...};};class Derived1: public Base {...};class Derived2: public Base {...};int main ( ) {int i;Base *p, b_ob;Derived1 ob1;Derived2 ob2;cout << «Тип i - » << typeid (i).name () << endl;p = &b_ob;cout << “p указывает на объект типа ” << typeid (*p).name () << endl;p = &ob1;cout << “p указывает на объект типа ” << typeid (*p).name () << endl;p = &ob2;cout << “p указывает на объект типа ” << typeid (*p).name () << endl;if ( typeid (ob1) == typeid (ob2) )cout << “Тип объектов ob1 и ob2 одинаков\n”;elsecout << “Тип объектов ob1 и ob2 не одинаков\n”;return 0;}Константные методыЕсли необходимо запретить методу изменять информационные членыобъектов класса, то при его описании используется дополнительныймодификатор const:<тип возвр.
значения> <имя функции> ( <пар-ры> ) const { <тело> }Описанные таким образом методы класса называются константными.•Если объект объявлен c модификатором const, то изменение егосостояния недопустимо. В таком случае все применяемые к этомуобъекту методы (кроме конструкторов и деструктора) должны иметьмодификатор const.•Данное требование является обязательным независимо от наличияили отсутствия информационных членов в классе.•Для защиты от изменения передаваемых фактических параметров втеле функции соответствующие формальные параметры такжеобъявляются с модификатором const: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; // ошибка!ob.f (); // ошибка!, если f() неконстантный метод}void f (const int * i, const myclass & ob) {i = NULL; // O.K.*i = 3; // ошибка!ob.f(); // ошибка!, если f() неконстантный метод}Статические члены класса.• Статические члены-данные и члены-функции описываются в классе сквалификатором static.• Статические члены-данные существуют в одном экземпляре и доступныдля всех объектов данного класса.• Статические члены класса существуют независимо от конкретныхэкземпляров класса, поэтому обращаться к ним можно еще до размещения впамяти первого объекта этого класса.• Необходимо предусмотреть выделение памяти под каждый статическийчлен-данное класса (т.е.
описать его вне класса с возможнойинициализацией), т.к. при описании самого класса или его экземпляровпамять под статические члены-данные не выделяется.• Доступ к статическим членам класса (наряду с обычным способом) можноосуществлять через имя класса (без указания имени соответствующегоэкземпляра) и оператор разрешения области видимости «::».Пример.class A {public:static int x;static void f (char c);};int A::x; // внимание! – размещение статического объекта впамятиvoid g() {…A::x = 10;…A::f ('a');…}Особенности использования статических методовкласса• Статические методы класса используются, в основном, дляработы с глобальными объектами или статическимиполями данных соответствующего класса.• Статические методы класса не могутнестатическими членами-данными класса.пользоваться• Статические методы класса не могут пользоватьсяуказателем this , т.е. использовать объект, от именикоторого происходи обращение к функции.• Статические методы класса не могут быть виртуальными иконстантными (inline - могут).Средства обработки ошибок.
Исключения в С++Обработка исключительных ситуаций в С++ организуется с помощью ключевых словtry, catch и throw.Операторы программы, при выполнении которых необходимо обеспечить обработкуисключений, выделяются в try-catch - блок.Если ошибка произошла внутри try-блока (в частности, в вызываемых из try-блокафункциях), то соответствующее исключение должно генерироваться с помощьюоператора throw, а перехватываться и обрабатываться в теле одного из обработчиковcatch, которые располагаются непосредственно за try-блоком.Исключение - объект некоторого типа, в частности, встроенного.Операторы, находящиеся после места генерации ошибки в try-блоке, игнорируются, апосле обработки исключения управление передается первому оператору, находящемусяза обработчиками исключений.
try-catch-блоки могут быть вложенными.Общий синтаксис try-catch блока:try {….. throw исключение; …..}catch (type) {---/*throw;*/}catch (type arg) {---/*throw;*/}…catch (…) {---/*throw;*/}Перехват исключений.С каждым try-блоком может быть связано несколько операторов catch. Онипросматриваются по очереди сверху вниз.Какой именно обработчик catch будет использоваться, зависит от типасгенерированного исключения.Выбирается первый обработчик с типом параметра, совпадающим с типомисключения. Ловушки с базовым типом (или с указателем или ссылкой на базовый тип)перехватывают все исключения с производным типом (или его адресом), т.е.производные типы должны стоять раньше базовых типов.Если исключение перехвачено каким-либо обработчиком catch, аргумент arg получаетего значение, которое затем можно использовать в теле обработчика.