Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Лекция № 3

Лекция № 3

ООП АФТИ ФФ НГУ 2017, осенний семестр

Avatar for Oleg Dashevskii

Oleg Dashevskii

October 03, 2017
Tweet

More Decks by Oleg Dashevskii

Other Decks in Education

Transcript

  1. ОПЕРАТОР ВЫЗОВА ФУНКЦИИ • operator() должен быть членом класса, других

    ограничений нет. • Активно используется в STL для создания функторов. • std::unary_function • std::binary_function • …
  2. template <class _Arg, class _Result> struct unary_function { typedef _Arg

    argument_type; typedef _Result result_type; }; template <class _Arg1, class _Arg2, class _Result> struct binary_function { typedef _Arg1 first_argument_type; typedef _Arg2 second_argument_type; typedef _Result result_type; }; template <class _Tp> struct plus : public binary_function<_Tp, _Tp, _Tp> { _Tp operator()(const _Tp& __x, const _Tp& __y) const { return __x + __y; } }; template <class _Tp> struct negate : public unary_function<_Tp, _Tp> { _Tp operator()(const _Tp& __x) const { return -__x; } };
  3. #include <iostream> #include <functional> #include <algorithm> using namespace std; int

    main () { int numbers[] {10, -20, -30, 40, -50}; int cx; cx = count_if(numbers, numbers+5, bind2nd(less<int>(), 0)); cout << "There are " << cx << " negative elements.\n"; return 0; }
  4. template <typename T> class undeletable_pointer { public: undeletable_pointer(T *ptr) :

    base(ptr) {} // ... private: void operator delete(void *); T *base; }; struct SomeObject { typedef undeletable_pointer<SomeObject> undeletable_ptr; undeletable_ptr operator&() { return this; } };
  5. class Err {}; class Giant {}; class Big { public:

    Big() { throw Err(); } }; class MyClass { Giant *giant; Big *big; public: MyClass(): giant(new Giant()), big(new Big()) {} ~MyClass() { delete giant; delete big; } }; int main() { try { MyClass myobject; } catch (Err) {} return 0; } К «умным» указателям
 (smart pointer) Решение: заменить указатели 
 объектами с объявленными 
 деструкторами
  6. template <typename T> class SmartPtr { T *ptr; public: SmartPtr(T

    *p) : ptr(p) {}; T& operator*() { return *ptr; } T* operator->() { return ptr; } ~SmartPtr() { delete ptr; } }; Первое приближение
  7. template <typename T> class SmartPtr { T *ptr; public: explicit

    SmartPtr(T *p = nullptr) : ptr(p) {} T& operator*() const { return *ptr; } T* operator->() const { return ptr; } SmartPtr(SmartPtr<T> &other) : ptr(other.release()) {} SmartPtr operator=(SmartPtr<T>& other) { if (this != &other) reset(other.release()); return *this; } ~SmartPtr() { delete ptr; } T *release() { T *oldPtr = ptr; ptr = nullptr; return oldPtr; } void reset(T *newPtr) { if (ptr != newPtr) { delete ptr; ptr = newPtr; } } };
  8. ПРЕОБРАЗОВАНИЕ ТИПА class Y { // ... }; ostream &operator<<(ostream

    &os, const Y &y); class X { // ... operator bool() const; operator Y() const; }; X x; if (x) { // ... } Y y(x); cout << x;
  9. class Point2D { int x; int y; public: Point2D(int p,

    int q) : x(p), y(q) {} friend class Point3D; }; class Point3D { int x; int y; int z; public: Point3D(int p, int q, int r) : x(p), y(q), z(r) {} Point3D(const Point2D &point2D) : x(point2D.x), y(point2D.y), z(0) {} friend ostream& operator<<(ostream& os, const Point3D& point); }; ostream& operator<<(ostream& os, const Point3D& point) { os << "(" << point.x <<", " << point.y << ", " << point.z << ")"; return os; } int main() { Point2D point2D(3, 4); cout << point2D << endl; return 0; }
  10. class complex { double re, im; public: complex(double r =

    0, double i = 0) : re(r), im(i) {} // ... }; bool operator==(complex, complex); void f(complex x, complex y) { x==y; // operator==(x,y) x==3; // operator==(x,complex(3)) 3==y; // operator==(complex(3),y) } Полезное неявное преобразование
  11. Неполезное неявное преобразование class Date { int d, m, y;

    public: Date(int dd = today.d, int mm = today.m, int yy = today.y); // ... }; void my_fct(Date d); void f() { Date d {15}; // 15-е число этого месяца // ... my_fct(15); // ОЙ d = 15; // хм... // ... }
  12. • Если у класса объявлен конструктор с одним аргументом, компилятор

    может делать «преобразование типа» путем создания временного объекта. • Ключевое слово explicit запрещает компилятору преобразовывать типы.
  13. void f(const Y &); class Y { Y(const X &);

    }; X x; f(x); ///////////////// class Array { public: Array(int size); }; Array a('?'); void f(const Y &); class Y { explicit Y(const X &); }; X x; f(x); // ОШИБКА ///////////////// class Array { public: explicit Array(int size); }; Array a('?'); // ОШИБКА
  14. struct A { // неявное преобразование в int operator int()

    const { return 100; } // явное преобразование в std::string explicit operator std::string() const { return "explicit"; } }; int main() { A a; int i = a; // OK - неявное преобразование std::string s = a; // Ошибка. Нужно явное преобразование std::string t = static_cast<std::string>(a); // OK } explicit преобразование типов
  15. NEW И DELETE // Глобальные функции void* operator new(size_t); void*

    operator new[](size_t); void operator delete(void *, size_t); void operator delete[](void *, size_t);
  16. // "Placement" new #include <new> // Поместить объект размером sz

    по адресу p void* operator new (size_t sz, void* p) noexcept; void* operator new[](size_t sz, void* p) noexcept; // Если p не нулевой указатель, пометить *p как неиспользуемое void operator delete (void* p, void*) noexcept; void operator delete[](void* p, void*) noexcept;
  17. class Arena { public: virtual void *alloc(size_t) = 0; virtual

    void *free(void *) = 0; // ... }; inline void *operator new(size_t sz, Arena *a) { return a−>alloc(sz); } extern Arena *Persistent, *Shared; void g(int i) { X *p = new(Persistent) X(i); X *q = new(Shared) X(i); // ... } void destroy(X *p, Arena *a) { p−> ̃X(); // ручной вызов деструктора (OMG!) a−>free(p); // освобождение памяти }
  18. class Employee { public: // ... void *operator new(size_t); void

    operator delete(void∗, size_t); void *operator new[](size_t); void operator delete[](void∗, size_t); }; class Manager : public Employee { /* ... */ }; Employee *p = new Manager; // ... delete p; // нужен виртуальный деструктор! // sizeof(Manager) будет передан вторым аргументом // в operator delete. Обычные new и delete для конкретного класса
  19. КОНСТАНТЫ ПОЛЬЗОВАТЕЛЬСКИХ ТИПОВ // Встроенное: 123 // int 1.2 //

    double 1.2F // float 'a' // char 1ULL // unsigned long long 0xD0 // hexadecimal unsigned "as" // C-style string (const char[3]) // Возможное: "Hi!"s // строка, а не массив char с нулём 1.2i // комплексное число 101010111000101b // двоичное число 123s // 123 секунды 123.56km // километры 1234567890123456789012345678901234567890x // расширенная точность
  20. constexpr complex<double> operator"" i(long double d) // мнимая константа {

    return {0,d}; } std::string operator"" s(const char *p, size_t n) // строковая константа { return string{p,n}; } template<typename T> void f(const T&); void g() { f("Hello"); // аргумент — const char * f("Hello"s); // аргумент — строка из 5 символов f("Hello\n"s); // аргумент — строка из 6 символов auto z = 2+1i; // complex{2,1} }
  21. • Целочисленная константа. Аргументы оператора: unsigned long long или const

    char * (или шаблон). 123m, 12345678901234567890X.
 • Константа с плавающей точкой. Аргументы оператора: long double или const char * (или шаблон). 12345678901234567890.976543210x, 3.99s. • Строковая константа. Аргументы оператора: (const char *, size_t). "string"s, R"(Foo\bar)"_path. • Символьная константа. Аргументы оператора: char, wchar_t, char16_t или char32_t. 'f'_runic, u'BEEF'_w.
  22. class X { public: // ... void operator=(const X&) =

    delete; void operator&() = delete; void operator,(const X&) = delete; // ... }; void f(X a, X b) { a = b; // ОЙ &a; // ОЙ-ОЙ a,b; // ОЙ-ОЙ-ОЙ } Удаление дефолтных версий операторов
  23. ОПЕРАТОРЫ И ПРОСТРАНСТВА ИМЁН Для бинарного оператора x@y, где x

    имеет тип X, а y – тип Y: • Если X – класс, поискать operator@ как член X или его базового класса. • Поискать operator@ в контексте выражения x@y. • Если X объявлен в пространстве имён N, поискать operator@ в этом пространстве имён. • Если Y объявлен в пространстве имён M, поискать operator@ в этом пространстве имён.
  24. ОПЕРАТОРЫ, КОТОРЫЕ НЕЛЬЗЯ ПЕРЕГРУЗИТЬ • ? : (тернарный) • .

    (доступ к члену класса) • .* (доступ к члену класса по указателю) • :: (namespace) • sizeof • alignof • typeid