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

Лекция № 3

Лекция № 3

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

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