
2 семестр
Основы программирования.
Напишем свой класс MyFunction
- Он шаблонный и принимает тип указателя на функцию. Как это сделать? Достаточно просто:
template<typename T>
MyFunction
- Теперь нам нужен конструктор, который принимает какой-то тип(функтор, функция), либо же 2 разных. Как всё же понять сигнатуру функционального объекта? Делаем специализацию шаблона вокруг другого шаблона:
template<typename R, typename Arg>
class MyFunction<R(Arg)>
- Почему не можем написать так сразу? Иначе специализируется то, чего не существует (то есть сразу, когда мы определяем шаблонный класс, у которого в скобках уже есть какой-то тип - это уже специализация)
- Нужен оператора скобки:
R operator()(Arg){
return R{};
}
- Нужен конструткор от типов:
private:
public:
MyFunction(TFuncPtr ptr){}
template<typename T>
MyFunction(T func){}
Как положить и лямбду, и функтор в указатель на функцию? — тип на поле класса
Type Eraser
- Как спрятать
TFunc
, чтобы в других методах его использовать (нельзя выразить черезR
иArg
)- Делаем чисто виртуальную структуру с чисто виртуальным оператором скобки и пишем её тип в поле
- Тогда всякий объект будет каститься к нему
- Чтобы это кастилось, создаём внутри класс, который наследуется от чисто виртуального класса
- Сделаем этот класс-ребёнок шаблонным и будет хранить поле на наш объект
В чём прикол?
- Мы в конструктор можем передавать объекты разного типа, которые имеют одну семантику: они принимают
аргументы
,оператор( )
ибебебе
- Прячем тип создаваемого объекта
- Внутри создаём класс, в который кладём этот тип, а этот класс работает семантичеки, также как и все объекты, которые мы хотим передавать
.
Касты
- implicit
- explicit
- const
- static
- dynamic
- reintepret
- C-style cast
Каст чиселок:
от меньшего ранга к большему(типа по размеру,
шорт
можно кинту
спокойно)каст если одинаковый
ранг
, но разныйsing
?любой указатель можно кастить к
войду
и отвойда
, да и все указатели можно друг к другу, потому что один и тот же размерс
юинт
что-то не то…неявно
0
кфолс
в форике
инт
сравнивается сансаинд лонг лонг
- то есть
знаковый тип
кастится кбеззнаковому
и происходит переполнение
- то есть
явный c-style cast
int i = 0;
std::cout << *(double*)&i
int i = 0;
int* p = &1;
double pd = (double*)p;
double d = *pd
в
инте
лежит сначала два последних байта, а потом два первыха вот
дабл
хранятся иначе, поэтому то же, что и дляинта
вдабле
принимается иначе + разный размер %%примерчик с классами%%в функцию пихаем указатель на другой объект
несмотря на то, что в другом объекте нет этого поля, поле и будет интерпретироваться как поле стр…
c-style cast - опасная штука, которая никак не проверяет, можем мы ли вообще это делать
const_cast
- убирает
const
илиvolatility
с переменной - может преобразовывать указатели на одинаковые типы данных
- может переобразовывать ссылки
[!example] Типичный пример если изначально объект константный, то даже после преобразований указателей, прога не будет арбайтен (UB) забота о работе конст каста лежит на программисте
[!example] Типичный пример в константном методе делать преобразования всё работает только тогда, когда сам объект изначально является неконстантным объектом
[!example] Типичный пример совместимость с c-кодом
static_cast
пытается преобразовать с помощью конструткоров и операторов приведения
работает в compile-time
работает для стандартных типов
работает для приведения указателей из одной иерархии
может приводить из указателя на
void
более явный
на этапе компилляции будет сказано, если сделать чего-то нельзя
b
преобразовывается к int
а int
кастится к float
который передаётся в конструктор для foo
…
[!example] Типичный пример преобразование классов, находящихся в одной иерархии во втором примерчике поля не присваиваются,
j
будет лежать послеi
, поэтому выведется мусор