Еще раз про экзамен
description
Transcript of Еще раз про экзамен
Еще раз про экзамен 22 мая – 10:00
Сбор у баобаба. Для тех, кто придет позже – будет объявление на расписании 3 курса
Вопрос 33 (RTTI и typeid) вычеркивается
Еще одна возможность сдать спец.курс будет в официальный день сдачи, 6 июня, в 10:00, сбор у баобаба
Задачи на 12 мая
Язык С++ - 2
Задача: из каких int состоит double? Вариант с union
union {double x;int a[2];
};
x = 2.71828;cout << a[0] << " " << a[1];
Вариант с преобразованием указателя
x = 2.71828;
int* p = (int*)&x;
cout << a[0] << " " << a[1];
Или лучше так:
int* p =reinterpret_cast<int*>(&x);
(см. ниже)
Задачи на 19 мая
Язык С++ - 4
ASSERT#ifdef DEBUG
#define ASSERT(cond) \ if (!(cond)) \
cout << "Условие " #cond "не выполняется";#else
#define ASSERT(cond)#endif
Cписок ошибок#define ERROR_TABLE map<int, string> errors;#define ERROR(num, message) errors[num] = message;
…ERROR_TABLEERROR(1, “Какая-то проблема“)ERROR(2, “Все плохо..“)ERROR(3, “У вас все неправильно“)
Еще про задачу о списке ошибокУсложним немного задачу:
Пусть я составил список ошибок, которые у меня будут выдаваться – с номерами и текстом ошибок. Но номера я записываю не как числа, а как символьные имена. И я бы хотел, чтобы с этими именами автоматически связывались числа 1, 2… по порядку.
Т.е. я хочу, чтобы я записал список ошибок в каком-то таком виде:
ERROR(someError, “Какая-то проблема“)ERROR(allBad, “Все плохо..“)ERROR(allWrong, “Все неправильно“)
И автоматически генерировалось что-то такое:
еnum {someError,allBad,allWrong,
};
map<int, string> errors;errors[someError] =
“Какая-то проблема“;errors[allBad] =
“Все плохо..“)errors[allWrong] =
“Все неправильно“;
Как это сделать?
Это будет еще одно домашнее задание, самое последнее, просто для тех, кому это будет интересно..
Прием: разные определения для одного и того же макроса Подсказка 1 – возможная схема
--- errlist.h --------------------------------ERROR(someError, “Какая-то проблема“)ERROR(allBad, “Все плохо..“)ERROR(allWrong, “Все неправильно“)
-- основная программа ----------------- … … определения, чтобы сгенерировать enum #include "errlist.h"
… определения, чтобы сгенерировать map #include "errlist.h"
Подсказка 2 – вам может потребоваться оператор препроцессора #undef #undef ABC Смысл: отменить определение ABC – нужно, если мы хотим его переопределить
Задача: Сколько квадратов?// Иерархия классов
class CShape {public:
virtual ~CShape() {}// Еще методы…
};
class CSquare : public CShape {// Методы…
};
class CCircle : public CShape { // Методы…
};
class CRhomb : public CShape { // Методы…
};
// Пример создания масива
vector<CShape*> v;v.push_back(new CCircle());v.push_back(new CSquare());v.push_back(new CRhomb());…
// Считаем количество квадратов
int cnt = 0;
for (vector<CShape*>::iterator p = v.begin(); p != v.end(); p++) {if (typeid(**p) == typeid(CSquare)) cnt++;
}
Замечание про RTTI
Почему плохо использовать RTTI? Когда это все-таки имеет смысл? Хочется использовать
typeid? Скорее всего, надо ввести виртуальную функцию.(smell…)
if (typeid(*p) == typeid(CCircle) cout << "Это круг";
else if (typeid(*p) == typeid(CSquare)cout << "Это квадрат";
else if (typeid(*p) == typeid(CTriang)cout << "Это треугольник";
cout << "Это " << p->name();
Когда все-таки имеет смысл использовать?
Если мы не можем добавить виртуальную функцию в базовый класс. (Например, классы, производные от CView)
Сортировка по последним n цифрам (с помощью функтора)class my_comparator {
int m; // 10^npublic:
my_comparator(int n){
// Calculate 10^nm = 1;for (int i = 0; i < n; i+
+) m *= 10;
}
bool operator() (int i, int j){
return i % m < j % m;}
};
my_comparator cmp(n);sort(v.begin(), v.end(), cmp);
или
sort(v.begin(), v.end(), my_comparator(n));
Снова сумма положительных элементов Так мы написали..
template <class T>typename T::value_type sumpos(T b, T e){ typename T::value_type sum;
for (T p = b; p!=e; p++) { if (*p > 0) { sum += *p; } } return sum;}
Просьба заказчика – пусть тип результата всегда int или double
T.e. требуется по одному типу найти другой по правилу: float, double double Все остальное int
Легко сказать – как это реализовать?
trait !
Язык С++ 13
Cумма положительных элементов – новое решениеtemplate <class T>struct sum_trait {
typedef int sum_type;};
template <>struct sum_trait<float> {
typedef double sum_type;};
template <>struct sum_trait<double> {
typedef double sum_type;};
#define SUM_TYPE \ typename sum_trait \ <typename T::value_type>:: \
sum_type
template <class T>SUM_TYPE sumpos(T b, T e){
SUM_TYPE sum = 0;
… дальше без изменений …
}
Язык С++ 14
casts(static_cast,
dynamic_cast и т.д.)
Оказывается, преобразования бывают 4 видов
Вместо существующего оператора преобразования рекомендуется выбрать один из 3 способов.
1. static_cast
Мы создаем объект, устроенный внутри по другому, но с тем же смыслом (примерно…)
Т.е. “другие биты, тот же смысл…”
T.e. раньше писали:
int i = (int)x;complex x = (complex)x;
Теперь рекомендуется писать:
int i = static_cast<int>(x);
2. reinterpret_cast double* px = &x;char* p = (char*) px;
Те же биты, другой смысл…Объект тот же, но мы его интерпретируем по другому.
Только в 3 случаях: указатель указатель указатель целое целое указатель
Т.е. рекомендуется писать:char* p =
reinterpret_cast<char*>(px);
const_cast3. const_cast
Пусть у нас есть const int* p;
Но мы точно знаем, что это не константа (просто неправильно описан параметр и т.д.). И очень надо ее поменять.
int* p1 = (int*)p;*p = 55;
Т.е. смысл тот же, биты те же. Только задаем или убираем спецификации const
Т.е. рекомендуется писать:
int* p1 = const_cast<int*>(p);
dynamic_castshape* p;
Пусть мы точно знаем, что p указывает на square
square* p1 = (square*)p;p1->… делаем что-то
специальное для квадрата
(Это называется downcasting)
Вообще-то можно проверить, действительно ли это квадрат.. По таблице вирт.функций Только если есть хотя бы
одна вирт. функция Должна быть включена
опция “Enable Runtime Type Info”
Можно написать так:square* p1 =
dynamic_cast<square*>(p);if (p1 == 0)
cout << "Ошибка!";
dynamic_cast - продолжениеТоже для ссылок:
shape& sh;square& p1 =
dynamic_cast<square&>(sh);
Если не то – исключение(bad_cast)
Заключение: Все виды cast лучше
применять пореже Но, если вы действительно
понимаете, зачем это вам надо – ОК, ничего страшного.
Namespace
Язык С++ 20
Зачем нужны namespace?Проблема:Пусть есть две библиотеки
классов:
Библиотека ABCLIB.класс stack …
Библиотека KLMLIB.класс stack
#include <abclib.h>#include <klmlib.h>
stack st; // Ошибка!
Решение: В библиотеке ABCLIB:namespace abc {
…class stack { ……
} То же в KLMLIB:namespace klm {
… class stack …
}
Теперь abc::stack и klm::stackЯзык С++ 21
Как обращаться к именам из namespace? Полное имя:
abc::stackklm::stack
using объявлениеusing abc::stack;
stack abc::stack
using директиваusing namespace abc;
stack пытается найти в abc
Замечания:
и using объявление и using директива действуют до конца блока.
Совет: в h файлах – только полное имя
Язык С++ 22
Еще возможности Инкрементальное
определение
namespace abc { … определения …}
… что-то вне namespace …
namespace abc { … еще определения …}
Глобальное пространство имен::f() – глобальная функция
using ::f;
M.б. вложенныеabc::klm
Язык С++ 23
Еще возможности - 2 Безымянные (анонимные)
namespace
namespace { int v; …} Генерируется уникальное имя + using директива
namespace <уник.имя> { int v; …}using namespace <уник.имя>;
Означает: Переменную v можно использовать только от того места, где она определена, и до конца файла
- примерно то же, что static
Язык С++ 24
Что мы не прошли…
Язык С++ - 25
Множественное наследование
Язык С++ - 26
Множественное наследование - 1class Car {// Автомобиль
…};
class Ship { // Корабль…
};
class Amphibia : public Car, public Ship {…
};
В реальности с множественным наследованием обычно получается довольно сложно…
Множественное наследование - 2Надо ли использовать?
Pазные точки зрения… Да
Например, ATL Нет
Например, MFC Да, но только для интерфейсов
(абстрактныe классов, вообще без кода, только с чисто виртуальными функциями) (Так в Java, например)
Diamond problem (ромбовидная диаграмма) А / \B1 B2 – наследники A \ / C – наследник B1, B2
diamond problem ромбовидная диаграмма
Проблема:class A {protected:
int x;void f();
};
Сколько в классе C экземпляров поля x? Хорошо бы один…
(например, поле "руль" или "мотор" для амфибии)
Vehicle (средство передвижения) поля "руль", "мотор"
/ \ Car Ship \ / Amphibia
Виртуальные базовые классыclass A { … }
class B1 : public virtual A { …
};
class B2 : public virtual A { …
};
class C : public B1, public B2 {…
};
Теперь x будет в C один раз Класс А называется "виртуальный базовый класс"
private и protected наследование
Язык С++ - 31
Пример Класс group - студенческая
группа.Представляется, как вектор из объектов класса student
class group {vector<student> vect;
public:void add(const student& s)void print() const;…
};
void group::add(const student& s){
vect.push_back(st);}
void group:: print() const{
…for (p = vect.begin(); p != vecn.end(); p++)
…}
То же с private наследованием Можно написать короче
class group : vector<student> {public:
void add(const student& s)void print() const;…
};
void group::add(const student& s){
push_back(st);}
void group:: print() const{
…for (p = begin(); p != end();
…}
Public наследование было бы неправильно!
private неследование – унаследованные меиоды становятся private Т.е. снаружи
наследование не видно…
protected наследование Примерно аналогично Встречается еще реже
Разные полезные вещи
Язык С++ - 35
Преобразования строка число atoi, itoa, atof, _fcvt и т.д.
строковые потоки
ostringstream sout;sout << i << " " << x;string s = sout.str();
И аналогично istringstream.
Форматный ввод/вывод в т.ч. в строку.
char s[20];sprinf(s, "%10.3lf", x);
Форматный вывод в MFC
CString s;s.Format("%10.3lf", x);
Функции с переменным числом аргументов #include <stdarg.h>
va_start, va_arg, va_end
int mysum(int n, …)
Вызов:cout << mysum(2, n, k);cout << mysum(4, i, j, k, l);
Не рекомендуется использовать:Нет проверки параметров компилятором: mysum(2, i, j, k) mysum(2, 3.14, "abc")
Но иногда удобно
Побитовые операции для целых чисел & - побитовое "И"
| - побитовое "ИЛИ"
^ - побитовое «исключающее ИЛИ»
~ - инвертировать виты
<< - сдвиг влево
<< - сдвиг влево
Еще возможности для работы с битами Битовые поля
class { int a:3; int b:4; int c:1;};
vector<bool>
bitset<n>
bitset<100> b;b[i] = true;if ( b[i] ) …
Полезные вещи в стандартной
библиотеке и в boost
Язык С++ - 40
shared_ptr Указатели со счетчиком ссылок
#include <memory>using namespace std::tr1;
{ shared_ptr<int> p(new int(56)); … {
shared_ptr<int> p1 = p;… // Два указателя на 56
} // Теперь только один …} // Теперь нет
указателей// Память
освобождается
shared_ptr Если не хотите думать о том,
когда освобождать память
class abc {shared_ptr<int> p;
public:abc() : p(new int(56)){}
// В деструкторе писать// ничего не надо
};
Для управления разделяемыми объектами
Алгоритмы, параметры у которых - функции (или функторы) find_if
bool isPos(int i){ return i > 0;}
find_if(v.begin(), v.end(), isPos);
Много такого типа remove_if transform for_each … и т.д.
Лично я почти никогда не использую…
Итераторы вставки, итераторы потоковcopy(v.begin(), v.end(), v1.begin());
С помощью copy можно дописать в конецcopy(v.begin(), v.end(), back_inserter(v1));
С помощью copy можно записать в файл
#include <iterator>…ostream_iterator<int> out_it(cout, “ “);copy(v.begin(), v.end(), out_it);
Еще в boost boost:: hash_map, hash_set
В C++ 0x – unordered_map, unordered_set
Вообще очень много чего (regex, graphs)
C++0x
Язык С++ - 46
C++ 0x – новый стандарт языкаТолько некоторые из новых
возможностей:
Инициализация контейнеров списком инициализации:
vector<int> v = {3, 7, 11 };
Цикл по контейнеру:
vector<int> v;for (x: v) { …
Вывод типа (type inference)
auto i = 3;auto x = 3.14;auto n = abc(x, y);
for (auto p = v.begin(); p != v.end(); p++)
lambdas Функция, параметр которой –
функция Пишем в параметре прямо
код функции
find_if(v.begin(), v.end(),[] (int x) { return x > 0; } );
sort(v.begin(), b.end(), [] (int x, int y) { return x % 10 < y % 10; } );
void f(vector<int> v, int n){
int m = 1;for (int i = 0; i < n; i++) m *= 10;
sort(v.begin(), b.end(), [] (int x, int y) { return x % m < y % m; } );
}
Conceptstemplate <class T>T max(T x, T y){
return y < x ? x : y;} template <Comparable T>T max(T x, T y){
return y < x ? x : y;}
concept Comparable<typename T> {bool operator<(T x, T y);
};
Более понятные сообщения об ошибках:
complex c1, c2;max(c1, c2);"Error: complex is not
Comparable"
Обнаружение ошибок еще в шаблоне:
template <Comparable T>T max(T x, T y) {
… max = x; …"operator = not in Comparable"
А вот что я сказал бы, если бы еще
было время…
Язык С++ - 50
main, cin, cout, cerrint main(int argc, char* argv[])
argc – количество параметров командной строки
argv – параметры
myprog aaa bbb ccc
argc = 4argv[0] = "myprog";argv[1] = "aaa";argv[2] = "bbb";argv[3] = "ccc";
cin, cout переназначаются !
myprog >abc.txtcout пишет в abc.txt
myprog <klm.txtcin читает из klm.txt
myprog >>abc.txtcout дописывает в конец abc.txt
cerr – не переназначается с помощью > (для сообщений об ошибках, например.
разное о new/delete, void* nothrow
int* p = new (nothrow) int [1000];
Не выбрасывать исключение (вернуть 0)
void* - указатель неизвестно на чтоОбязательно надо потом преобразовывать
placement new
char s[10000];abc* p = new ((void*)s) abc;
Явный вызов деструктора
p->~abc();
pointers to members Pointers to members
class abc { int a; int b; int c; int d; …};
int abc::* p; // Какое-то // целое поле в abc
p = abc::d;abc x;x.*p = 56;
Чаще применяется для методов:
class abc { void draw(); void print(); void clear(); void save();
…};
myfunc(abc::print);
extern "C" extern "C"
--- abc.h ------------------------------extern "C" void f(int i);
// Определено в C файле (не в C++)----------------------------------------
Разные замечания Наследование и перегрузка
методов
class B {public:
void f(int i);};
class D : public B {public:
void f(const char* s);
};D x;x.f(5); // Ошибка
Виртуальные функции в конструкторе и деструкторе
Переопределение оператора ++.x++ и ++x ??operator++(); // ++xoperator++(int); // x++
И это все…И главное, что не успел
сказать – лично мне было очень интересно, может быть
и вам тоже!
Язык С++ - 56