188 lines
4.0 KiB
Markdown
188 lines
4.0 KiB
Markdown
# Семинар 6
|
|
|
|
## RTTI - Run Time Type Identification
|
|
|
|
- typeid
|
|
- dynamic_cast
|
|
|
|
### typeid
|
|
|
|
> `typeid` возвращает тип объекта/указателя. Если указатель на класс с виртуальными функциями, вернёт именно тип объекта. Иначе - указателя.
|
|
|
|
Для `type_info` переопределённые операции и методы:
|
|
|
|
- ==
|
|
- !-
|
|
- .name
|
|
|
|
```cpp
|
|
class A {
|
|
public:
|
|
virtual void f() {}
|
|
};
|
|
|
|
class B : public A {};
|
|
|
|
int main () {
|
|
A *pa = new B;
|
|
B *pb;
|
|
std::cout << typeid(*pa).name; // 1B (1 символ в имени)
|
|
if (typeid(*pa) == typeid(B)) {
|
|
pb = (B*)pa; // небезопасное приведение
|
|
}
|
|
}
|
|
```
|
|
|
|
## Dynamic cast
|
|
|
|
```cpp
|
|
class A {
|
|
public:
|
|
virtual void f() {}
|
|
};
|
|
|
|
class B : public A {};
|
|
|
|
int main () {
|
|
A *pa, a;
|
|
B *pb, b;
|
|
pa = &b;
|
|
// безопасно приводит, вернёт не NULL в случае успеха
|
|
pb = dynamic_cast<B*>(pa);
|
|
}
|
|
```
|
|
|
|
```cpp
|
|
class A {
|
|
public:
|
|
virtual void f() {}
|
|
};
|
|
|
|
class B : public A {};
|
|
|
|
int main () {
|
|
A *pa, a;
|
|
B *pb, b;
|
|
A &pr = a;
|
|
// B &rb = dynamic_cast<B&>(pa); // выкинет bad_cast
|
|
}
|
|
```
|
|
|
|
## Исключения
|
|
|
|
`try - throw - catch`
|
|
|
|
`terminate()` - в случае, если ничего не обработалось
|
|
|
|
приводится в `catch` указатели к константным могут
|
|
|
|
```cpp
|
|
int f() {
|
|
try {
|
|
...
|
|
throw 10;
|
|
...
|
|
throw "abc";
|
|
...
|
|
throw A();
|
|
...
|
|
} catch (int a) {
|
|
...
|
|
throw ...; // тогда обработается функцией выше
|
|
...
|
|
} catch (const char* s) {
|
|
...
|
|
} catch (A &x) {
|
|
...
|
|
} catch (...) { // все остальные исключения
|
|
|
|
}
|
|
}
|
|
```
|
|
|
|
В случае возвращение класса, который наследуется от базового, "ловить" надо сначала производный, после - базовый
|
|
Деструктор для создаваемого класса вызывается только после фулл обработки исключения (если catch сам вызвал throw)
|
|
|
|
```cpp
|
|
int f() throw(int, char) {
|
|
try {
|
|
...
|
|
throw 1.2;
|
|
...
|
|
} catch (double) {
|
|
...
|
|
}
|
|
}
|
|
```
|
|
|
|
`unexpected()` - вызывается, если мы на внешнюю функцию передаём исключение типа, который не указан
|
|
|
|
```cpp
|
|
// никакие не передавать вовне
|
|
int f() throw();
|
|
|
|
after c++17 only:
|
|
int f() noexcept;
|
|
```
|
|
|
|
### Алгоритм обработки исключений
|
|
|
|
- создание временного объекта типа возвращаемого исключения
|
|
- уничтожение объектов в `try` блоке
|
|
- выход из `try`
|
|
- подбор нужного обработчика
|
|
- если больше исключений нет - деструктор временного объекта
|
|
- если не обработано - выход к внешнему обработчику
|
|
|
|
```cpp
|
|
5.14. Что напечатает следующая программа?
|
|
struct S {
|
|
S ( int a) {
|
|
try {
|
|
if (a > 0) throw *this ;
|
|
else if (a < 0) throw 0;
|
|
}
|
|
catch ( S & ) {
|
|
cout << “SCatch_S&” << endl;
|
|
} catch (int ) { throw ; }
|
|
cout << “SConstr” << endl;
|
|
}
|
|
S (const S & a) { cout << “Copy” << endl; }
|
|
~S ( ) { cout << “Destr” << endl; }
|
|
};
|
|
int main ( ) {
|
|
try {
|
|
S s1( 0 ), s2 ( 5 );
|
|
cout << “Main” << endl;
|
|
}
|
|
catch (S &) { cout << “MainCatch_S&” << endl; }
|
|
catch ( ... ) { cout << “MainCatch_...” << endl; }
|
|
|
|
return 0;
|
|
}
|
|
```
|
|
|
|
Результат отработки программы:
|
|
|
|
```text
|
|
Sconstr
|
|
Copy
|
|
Scatch_s&
|
|
Destr
|
|
Sconstr
|
|
Main
|
|
Destr
|
|
Destr
|
|
```
|
|
|
|
1
|
|
14
|
|
15
|
|
CatchB
|
|
bad_cast
|
|
63
|
|
63
|
|
3
|
|
...
|
|
End
|