Главная » Просмотр файлов » полный C++ полностью одобренные Димой и одобренные Мишей

полный C++ полностью одобренные Димой и одобренные Мишей (1119617), страница 5

Файл №1119617 полный C++ полностью одобренные Димой и одобренные Мишей (Коллоквиум. Варианты заданий и ответы) 5 страницаполный C++ полностью одобренные Димой и одобренные Мишей (1119617) страница 52019-05-09СтудИзба
Просмтор этого файла доступен только зарегистрированным пользователям. Но у нас супер быстрая регистрация: достаточно только электронной почты!

Текст из файла (страница 5)

pd = &d;

pb = dynamic_cast<Base*> (pd); // а так тоже можно

В C++ рекомендуется не делать статических явных преобразований типа. В нашем случае можно было написать pd = (Derived*)pb, но это плохо, так как нет контроля, а при динамическом кастинке тип преобразуется, только если это будет разумно.

Кстати, есть ещё один вариант операции: dynamic_cast<T&> (r);

Если ни одно из двух условий не выполняется, то генерируется исключение bad_cast (только для ссылок!).

Также есть операция typeid (об’ект) или typeid (имя_типа), которая возвращает ссылку на об’ект класса typeinfo. В нём перегружены операции сравнения и определена функция, возвращающая имя типа:

bool operator== (const typeinfo&);

bool operator!= (const typeinfo&);

const char* name ();

А вот так их можно использовать:

if (typeid(*pb) == typeid(Derived))

pd = dynamic_cast<Derived*> (pb);

// уже не нужно проверять pd != NULL

cout<<typeid(*pb).name()<<endl; // визуализация – узнать тип *pb

Есть ещё три оператора, которыми можно не пользоваться, потому что их не было в C. Но при программировании на C++ их лучше писать.

static_cast – отличается от dynamic_cast отсутствием проверок:

pd = static_cast<Derived*> (pb);

reinterpret_cast – значению одного указателя можно присваивать значение любого другого указателя (обычно используется для «принципиально различных» типов):

p = reinterpret_cast<int*> (q); // эквивалентно p = (int*)q;

const_cast – преобразование снятия константности.



Множественное наследование.

Множественное наследование - ситуация, когда производный класс создаётся на базе нескольких базовых классов.

Чтобы понять, зачем это нужно, можно привести пример от Бьярна Страуструпа. При программировании некого GUI у нас есть класс ‘окно’. От него есть производные классы: ‘окно с рамкой’ и ‘окно с меню’. А что если мы хотим создать окно с рамкой и с меню? Нам на помощь приходит множественное наследование.

Пример. Далее приведём чисто технический пример, который не несёт никакой смысловой нагрузки, но на котором можно показать синтаксис.

class A { ... };

class B { ... };

class C: public A, public B { ... };

Базовый класс не может появиться несколько раз в этом списке явно (ситуация ‘одна база – два раза’). Однако может возникнуть такая ситуация:

class L { public: int n; ... };

class A: public L { ... };

class B: public L { ... };

class C: public A, public B { ... };

Например, мы напишем: C.c; c.n = 0; Возникает неоднозначность: какую c нам вызвать, ту которая пришла к нам через A, или же ту, которая наследовалась через B. Здесь мы можем уточнить: c.A::n = 5; или c.B::n = 7;. Перед оператором разрешения контекста мы указываем точку, от которой начинается поиск переменной.

Теперь понятно, что мы имели ввиду под однозначным классом ранее, когда говорили о динамическом полиморфизме.

C *pc = new C;

L *pl = pc; // неверно

C неоднозначен, так как в нём ‘содержатся’ два L.

L *pl = (L*)(A*)pc; // а так можно!

L *pl = (L*)(B*)pc; // или так...

Но у нас может возникнуть вполне законное желание, чтобы в C был только один экземпляр L. Для этого придумали виртуальные базовые классы.



Виртуальные базовые классы.

c lass L { public: int n; ... };

class A: virtual public L { ... };

class B: virtual public L { ... };

class C: public A, public B { ... };

C *pc = new C;

L *pl = pc; // верно

Теперь мы можем присваивать указателю на базовый класс указатель на производный, поскольку второй доступен и однозначен. Заметим, что при наследовании со словом virtual никакой виртуализации функций не происходит, просто совпадают ключевые слова, видимо, из-за плохой фантазии создателей языка.

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

class A {

public: int a;

void f (int);

void g();

...

};



class B {

int a;

void h (char);

public: void f ();

int g;

void h ();

void h (int);

...

};



class C: public A, public B { ... /* нет плохих имён */};



void blablabla (){

C c;

c.a = 1; // неоднозначность

Используемые для имён классов проверки производятся в таком порядке:

  1. контроль однозначности в разных классах (втупую, считая все члены равноправными и доступными) - в разных классах в подобных ситуациях не должно быть одинаковых имён;

  2. попытка разрешить вызов (определение, какая из перегруженных функций вызовется);

  3. контроль доступности того, что выбрали.

c.f(1); // ошибка, 1 пункт

c.f(); // ошибка, 1 пункт

c.g(); // ошибка, 1 пункт

c.g = 1; // ошибка, 1 пункт

c.h(); // всё хорошо

c.h(1); // всё хорошо

c.h(‘a’); // ошибка доступа, пункт 3

c.A::g(); // можно, мы явно сказали, что вызывать

}

Лучше явно указывать, откуда мы хотим вызвать функцию, так как может оказаться, что мы случайно унаследовали что-то лишнее. Особенно это актуально, когда мы пользуемся библиотечными классами из разных библиотек.



Агрегация. Композиция.

При агрегации возникает проблема вызова конструктора.

Пусть нам нужно построить частотный словарь. Для строк есть конструктор

class String { ...

public: String (const char *);

};

class Word{

String data;

int count;

public: Word (const char *s, int count = 1): data(s)

{ this->count = count;}

};

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

Если членом класса является константа или ссылка, то тоже необходимо использовать инициализаторы.

class X {

int t;

const int k;

int& r;

...

public: X (int i): k(i), r(t) { t = i; }

};



Статические члены класса.

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

В C++ также можно использовать ключевое слово static внутри класса. Если мы описываем статическое поле, то оно создаётся в одном экземпляре и используется всеми об’ектами данного класса. Переменная инициализируется ещё до создания первого об’екта данного класса.

class X {

public: int a;

static int count; // счётчик созданных об’ектов

X (int i) { a = i; ++count;}

...

};

int X::count = 0; // в классе этого сделать нельзя!

По умолчанию все статические члены инициализируются нулями.

int main (){

cout<<X::count<<endl; // получим ноль. count инициализирован

X g(1), z(10);

cout<<g.count<<endl<<z.count<<endl; // две двойки

return 0;

}

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

Даже если сделать статический член класса скрытым, его всё равно можно будет инициализировать. Но тогда мы не сможем её напрямую получить, и в классе нужно описать функцию-геттер или выводящую функцию:

void printCount () { cout<<count; }

Эту функцию мы сможем вызвать, только если есть об’екты данного класса. Однако эту функцию можно тоже сделать статической. Нужно учитывать, что статические функции используют только статические поля класса, то есть она должна уметь работать независимо от об’ектов класса. Естественно, в статической функции не определён указатель this.

static void printCount () { cout<<count; }



Библия специальных функций-членов класса by ТВ.

Обычный конструктор вызывается:

  • при создании об’екта соответствующего класса, в том числе для элементов массива – конструктор умолчания;

  • при создании об’ектов в динамической памяти;

  • если об’ект – член другого класса (агрегация);

  • при создании об’екта производного класса вызываются конструкторы базовых (если ничего специально не напишем, то дефолтный конструктор будет пытаться вызваться);

  • для статических членов, являющихся об’ектами другого класса.

Конструктор копирования вызывается:

  • при инициализации об’екта;

  • при передаче в функцию параметра по значению (без амперсанда);

  • при возврате результата функции по значению;

  • при выбрасывании исключения пользовательского типа (читай дальше).

Деструктор вызывается:

  • при выходе из зоны описания локального об’екта;

  • при выполнении delete для указателя, полученного по new;

  • при явном вызове деструктора;

  • при свёртке стека (читай дальше).

Исключительные ситуации в C++

Существуют различные способы обработки ошибок:

  • прекратить работу программы (вызов exit()); метод плох тем, что глубинные функции не должны иметь таких полномочий;

  • специальный результат функции (так любят делать библиотечные функции C), например, NULL или -1; однако не всегда можно придумать значение, которое не может получиться в результате работы функции;

  • формирование некоторого признака (например, переменная errno); однако программисты не любят постоянно проверять его значение, также метод даёт сбои в некоторых ситуациях при параллельном программировании;

  • вывод на экран диагностики; это не даёт ответа, что делать дальше.

Идея исключений в следующем: отделить код, обрабатывающий входные данные, от кода, реагирующего на проблему.

Общая схема:

try {

// подверженный ошибкам код

if (ошибка) throw выражение;

}

catch (тип1 параметр) { ... }

catch (тип2 параметр) { ... }

Сначала мы входим в try, как будто его и нет вовсе. Если вдруг мы попадаем на инструкцию throw, то код ниже неё не выполняется, а управление передаётся. Среди параметров catch ищем подходящий тип исключения. Если находим, то выполняются действия в нём. Там может быть любой код, можно также использовать значение параметра. Когда инструкции выполнятся, переходим на оператор после последнего catch.

Обработчики могут быть трёх видов:

  • catch (тип параметр) { ... }

  • catch (тип) { ... } // не интересно значение параметра

  • catch (...) { ... } // обрабатывает любое исключение

Обработчик исключения catch типа T может обработать исключение типа E, если:

  • T и E одного и того же типа (с точностью до typedef)

  • T однозначный и доступный базовый класс к E;

  • T, E – указатели, E может быть преобразован к T с помощью стандартных преобразований (указатель на производный класс приводится к указателю на однозначный доступный базовый класс, любой указатель приводится к void* ; здесь 0 не преобразуется к NULL)

Вместо T также могут появиться const T, T&, const T&.

Важен порядок, в котором перечислены обработчики обработчики:

catch (void *) { ... } // все указатели попадут сюда

catch (char *) { ... } // так что этот обработчик не работает

catch (...) { ... }

catch (тип) { ... } // а до этого обработчика не доберется

// вообще ни одно исключение

Характеристики

Список файлов ответов (шпаргалок)

Свежие статьи
Популярно сейчас
Почему делать на заказ в разы дороже, чем купить готовую учебную работу на СтудИзбе? Наши учебные работы продаются каждый год, тогда как большинство заказов выполняются с нуля. Найдите подходящий учебный материал на СтудИзбе!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает - и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе "Студизба"
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Популярные преподаватели
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
6361
Авторов
на СтудИзбе
310
Средний доход
с одного платного файла
Обучение Подробнее